mongoid中嵌入关系的真实多态性

时间:2013-11-27 17:15:47

标签: ruby mongoid polymorphic-associations

使用Mongoid3,我试图将多态性添加到我的嵌入式关系中。

我有一个课程Item必须 embed_one 包含我的信息的对象。 这笔交易是:
  - 我的对象的类型可以是其中之一:CalendarStickerPicture;
  - 无论我的对象类型如何,我都希望通过一个独特的“密钥”来访问它: detail
例如:

pry> my_item1.detail  
=> `<Picture _id: 1234>`  
pry> my_item2.detail  
=> `<Sticker _id: 8964>`
pry>

首先,我尝试使用关键字 as polymorphic ,如下所述:https://github.com/mongoid/mongoid/issues/902
例如:

class Item
    include Mongoid::Document
    embeds_one  :detail, as: :item_slot
end

class Picture
    include Mongoid::Document
    embedded_in :item_slot, polymorphic: true
end

class Calendar
    include Mongoid::Document
    embedded_in :item_slot, polymorphic: true
end

class Sticker
    include Mongoid::Document
    embedded_in :item_slot, polymorphic: true
end

然后我试图访问我的详细信息但不幸的是,我收到此消息错误:

pry(main)> i = Item.new
pry(main)> i.detail
=> nil
pry(main)> i.detail = Picture.find('50b864').dup
pry(main)> i.save
=> true
pry(main)> i = Item.find i._id
pry(main)> i.detail
NameError: uninitialized constant Detail
from /home/jg/.rvm/gems/ruby-1.9.3-p448/gems/activesupport-3.2.14/lib/active_support/inflector/methods.rb:230:in `block in constantize'

它说mongoid没有找到任何.detail进入我的item。为什么不。

然后,我发现此主题mongoid polymorphic association error告诉您添加 class_name 。所以我更新了我的代码:

class Item  
    include Mongoid::Document
    embeds_one  :detail, class_name: "Picture", class_name: "Calendar", class_name: "Sticker"
end

让我们试试:

pry(main)> i.detail = Picture.find('50b864').dup
pry(main)> i.save
=> true
pry(main)> i = Item.find i._id
pry(main)> i.detail
=> #<Sticker _id: 52961d>

这令人尴尬,因为我期待得到一个Picture,而不是一个Sticker (它里面有我的图片的值)。 (如果我在新行上放置每个不同的 class_name 值,结果都是一样的。)

对于我的第三次尝试,我使用了Custom Relation Names,如此:

class Item  
    include Mongoid::Document
    embeds_one  :detail, class_name: "Picture", class_name: "Calendar", class_name: "Sticker", inverse_of: :item_slot
end

class Picture # for Calendar and Sticker too ofc
    include Mongoid::Document
    embedded_in :item_slot, polymorphic: true, inverse_of: :detail
end  

但它也给了我贴纸 我甚至尝试过:

class Item  
    include Mongoid::Document
    embeds_one  :detail, inverse_of: :item_slot
end  

但它再次向我发送了之前看到的NameError。

我的最后一次尝试是使用继承:

class Item  
    include Mongoid::Document
    embeds_one :detail
end

class Detail
    include Mongoid::Document
    embedded_in :item
end

# Same again for Calendar and Sticker
class Picture < Detail
    ... # regular other fields
end  

但是当它为sticker.rb和calendar.rb

打包 pry 时,它给了我很糟糕的信息。
 DEVEL -  Failed to load .../models/sticker.rb; removing partially defined constants
 DEVEL -  Problem while loading .../models/sticker.rb: uninitialized constant Detail  

我不知道..
==&GT;有人提示吗?

编辑
如果像Extract `Moped::BSON::Document` attributes in Ruby hash那样有Hash[e.attributes]的等价物,那就太好了,然后就这样做了:

class Item
    include Mongoid::Document
    field :detail
end  

PictureCalendarSticker保留为类实例(因为我保存后每种方法都有不同的方法)。

JG

编辑:替代方式
编辑08/08/2014,将该部分拆分为该主题的答案。

3 个答案:

答案 0 :(得分:5)

你应该使用多态关系的继承 你走了:

  

基类

class Resource
  include Mongoid::Document
  include Mongoid::Timestamps

  embedded_in :resoursable, polymorphic: true
end
  

儿童的

class Photo < Resource
  field :width,  type: Integer
  field :height,  type: Integer
end

class Video < Resource
  field :url,  type: String
end
  

嵌入

class Post
  include Mongoid::Document
  include Mongoid::Timestamps

  embeds_one :media, as: :resoursable, class_name: 'Resource'
end
  

p = Post.last
resource = Photo.new
p.media = resource
p.save!

答案 1 :(得分:1)

好吧,似乎在Mongoid github.com/mongoid/mongoid/issues/2560中还不可能。所以,我做了类似的事情:

class Item
    include Mongoid::Document
    embeds_one :picture
    embeds_one :sticker
    embeds_one :calendar

    # attributes to the right field the document to embed
    def detail=(my_object)
        send("#{my_object.class.to_s.downcase}=", my_object)
        detail
    end

    # returns the embedded object
    def detail
        picture || sticker || calendar
    end
end

# Similar to Sticker and Calendar
class Picture
    embedded_in :item
end

如果有人有更好的答案,我会接受它! 无论如何,希望它能帮助我的下一个。

答案 2 :(得分:1)

今天我遇到了类似的问题,我发现Mongoid4已经解决了这个问题。

class Item
  include Mongoid::Document
  embeds_one :detail
end

父班

class Detail
  include Mongoid::Document
  embedded_in :item
end

儿童班

class Picture < Detail
end

class Sticker < Detail
end

class Calendar < Detail
end
i = Item.new
i.detail = Picture.new
i.save
i.detail

#<Picture _id: 6b78d7866289a63078, _type: "Picture">