Search code examples
ruby-on-railsrubymongoid

Two different models embedding the same model


I've got two very similar collections. The only difference between both is that one (Item1) has more details than the other (Item2). Documents in both collections already have embedded "Detail" documents:

Item1:

{
    "_id" : ObjectId("5461c8f0426f727f16000000"),
    "n" : "Name 1",
    "detail" : {
        "d" : [ 
            "Frank Darabont"
        ],
        "a" : [ 
            "Tim Robbins", 
            "Morgan Freeman", 
            "Bob Gunton"
        ]
}

Item2:

{
    "_id" : ObjectId("5461c8f0426f727f16000000"),
    "n" : "Name 1",
    "detail" : {
        "d" : [ 
            "Frank Darabont"
        ]
}

I would like to let "detail" field be the same in both documents. I have both models Item1 and Item2 in the same app and they both have "Detail" embedded. The solutions I've seen for this is to call :detail different in both models but that doesn't work, as it looks in the Item(1|2) document for a subdocument that doesn't exist, returning nil. I have it like this right now:

class Item1
  include Mongoid::Document

  embeds_one :detail1, :class_name => "Detail"

  field :n
end

class Item2
  include Mongoid::Document

  embeds_one :detail2, :class_name => "Detail"

  field :n
end

But, in order to retrieve the "detail" subdocument, I would like to have something like:

class Item1
  include Mongoid::Document

  embeds_one :detail, as: :detail1, :class_name => "Detail"

  field :n
end

class Item2
  include Mongoid::Document

  embeds_one :detail, as: :detail2, :class_name => "Detail"

  field :n
end

This doesn't do what I expect. Is there a way to achieve what I want or changing Detail documents to have different names in each collection is the only solution? :

Thanks.


Solution

  • From the fine manual:

    Polymorphism

    When a child embedded document can belong to more than one type of parent document, you can tell Mongoid to support this by adding the as option to the definition on the parents, and the polymorphic option on the child. On the child object, an additional field will be stored that indicates the type of the parent.

    They even include an example (non-embedded parts left out for clarity):

    class Band
      include Mongoid::Document
      embeds_many :photos, as: :photographic
    end
    
    class Photo
      include Mongoid::Document
      embedded_in :photographic, polymorphic: true
    end
    

    You should be able to set it up like this:

    class Item1
      include Mongoid::Document
      embeds_one :detail, as: :detailable
    end
    class Item2
      include Mongoid::Document
      embeds_one :detail, as: :detailable
    end
    class Detail
      include Mongoid::Document
      embedded_in :detailable, polymorphic: true
    end