Rails3 対応 MongoDB ORM、Mongoid 詳解―継承

Mongoid はドキュメントとエンベッドされたドキュメントの継承をサポートしています。以下のドメインモデルを考えてみます。

class Canvas
  include Mongoid::Document
  field :name
  embeds_many :shapes

  def render
    shapes.each { |shape| shape.render }
  end
end

class Browser < Canvas
  field :version, :type => Integer
end

class Firefox < Browser
  field :useragent
end

class Shape
  include Mongoid::Document
  field :x, :type => Integer
  field :y, :type => Integer

  embedded_in :canvas, :inverse_of => :shapes

  def render
    #...
  end
end

class Circle < Shape
  field :radius, :type => Float
end

class Rectangle < Shape
  field :width, :type => Float
  field :height, :type => Float
end

上記の例で、Canvas、Browser、Firefox は全て canvases コレクションの中に保存されます。データベースから正しいドキュメントが帰ってくるように、追加のアトリビュート _type が保存されます。また、これは、Circle、Rectangle、Shape といった、エンベッドされたドキュメントにも適用されます。フィールドとバリデーションも子に継承されますが、親には適用されません。子クラスは親クラスの全てのフィールドとバリデーションを含みますが、逆はありません。

子クラスへのクエリ

子クラスへのクエリは通常のクエリと変わりません。ドキュメントはすべて同じコレクションですが、クエリは、正しい型のドキュメントのみ返します。

Canvas.where(:name => "Paper") # Canvas ドキュメントと子クラスを返します
Firefox.where(:name => "Window 1") # Firefox ドキュメントだけ返します

関連

通常の代入を通してか、関連の build や create メソッドを通して、has_one または has_many 関連の、どの型の子クラスも追加できます:

firefox = Firefox.new
firefox.shapes.build({ :x => 0, :y => 0 }) # Shape オブジェクトを作成します
firefox.shapes.build({ :x => 0, :y => 0 }, Circle) # Circle オブジェクトを作成します
firefox.shapes.create({ :x => 0, :y => 0 }, Rectangle) # Rectangle オブジェクトを作成します

rect = Rectangle.new(:width => 100, :height => 200)
firefox.shapes


継承は以上です。