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 と明らかに振る舞いが異なるので、作者の気が変わったようだ。
