Rails で MongoDB を使ってみた(2)
2010/03/25
前回に引き続き、MongoDB で Rails アプリを作る話。
今回は関連づけに挑戦だ。
参考資料:
app/documents/person.rb に has_one :address
を追加。
class Person include Mongoid::Document field :first_name field :last_name has_one :address def full_name "#{first_name} #{last_name}" end end
app/documents/address.rb を作成。ただし、ほとんど参考資料からのパクリ。
class Address include Mongoid::Document field :street field :city field :state field :post_code belongs_to :person, :inverse_of => :address def to_s [ street, city, state, post_code ].select { |value| value.present? }.join(', ') end end
app/views/people/_form.html.erb
<% form_for @person do |f| %> <%= f.label :first_name %> <%= f.text_field :first_name %><br /> <%= f.label :last_name %> <%= f.text_field :last_name %><br /> <fieldset> <legend>Address</legend> <% f.fields_for :address do |g| %> <%= g.label :street %> <%= g.text_field :street %><br /> <%= g.label :city %> <%= g.text_field :city %><br /> <%= g.label :state %> <%= g.text_field :state %><br /> <%= g.label :post_code %> <%= g.text_field :post_code %><br /> <% end %> </fieldset> <%= f.submit %> <% end %>
app/views/people/new.html.erb
<h1>People#new</h1> <%= render :partial => 'form' %>
app/views/people/edit.html.erb
<h1>People#edit</h1> <%= render :partial => 'form' %>
app/views/people/show.html.erb
<h1>People#show</h1> First Name: <%= @person.first_name %><br /> Last Name: <%= @person.last_name %><br /> Address: <%= @person.address %><br /> <%= link_to 'List', :people %>
これで完成。ほとんど ActiveRecord と同じように使えることが分かった。
さて参考文献によれば、実際には Person オブジェクトと Address オブジェクトが「関連づけられる」というより、Address オブジェクトがハッシュとして Person オブジェクトに「埋め込まれる」ようだ。
ちょっと説明しづらいが、RDBMSと対比すると理解しやすいだろう。
RDBMSでは persons テーブルと address テーブルにそれぞれ 1 つずつレコードがあって、これらの2つのレコードが関連づけられる。
しかし、MongoDB は「ドキュメント」を集合として管理するデータベースだ。
つまり JSON で
{ first_name: "Tsutomu", last_name: "Kuroda", address: { street: "30 Rockefeller Plaza", city: "New York", state: "NY", post_code: "10112" } }
と表現できるようなオブジェクトを丸ごとデータベースに放り込む。
ただし、person.rb の has_one を has_one_related に変更すれば、Address オブジェクトはコレクションの要素としてデータベースに格納されるようになる。この場合、Person オブジェクトには Address オブジェクトの id だけが記録される。
http://github.com/durran/mongoid/ で最新のコードを見ると、has_one メソッドは embed_one メソッドに名前が変わっている。ActiveRecord と明らかに振る舞いが異なるので、作者の気が変わったようだ。