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
In the above example, Canvas, Browser and Firefox will all
save in the canvases collection. An additional attribute _type is stored in
order to make sure when loaded from the database the correct document is returned. This
also holds true for the embedded documents Circle, Rectangle, and
Shape. Fields and validations are inherited down the hierachy, but not up. A
subclass will contain all of its parent's fields and validations, but not vise-versa.
Querying for Subclasses
Querying for subclasses is handled in the normal manner, and although the documents
are all in the same collection, queries will only return documents of the correct type,
similar to Single Table Inheritance in ActiveRecord.
Canvas.where(:name => "Paper") # Returns Canvas documents and subclasses
Firefox.where(:name => "Window 1") # Returns only Firefox documents
Associations
You can add any type of subclass to a has one or has many association, through either
normal setting or through the build and create methods on the
association:
firefox = Firefox.new
firefox.shapes.build({ :x => 0, :y => 0 }) # Builds a Shape object
firefox.shapes.build({ :x => 0, :y => 0 }, Circle) # Builds a Circle object
firefox.shapes.create({ :x => 0, :y => 0 }, Rectangle) # Creates a Rectangle object
rect = Rectangle.new(:width => 100, :height => 200)
firefox.shapes