使用 Mongoid3,我正在尝试为我的嵌入式关系添加多态性。
我有一个类Item
,它必须embed_one包含我信息的对象。交易是:
- 我的对象的类型可以是其中之一:Calendar
、Sticker
、Picture
;
- 无论我的对象类型如何,我都想通过唯一的"键"访问它:详细信息
例如:
pry> my_item1.detail
=> `<Picture _id: 1234>`
pry> my_item2.detail
=> `<Sticker _id: 8964>`
pry>
首先,我尝试使用关键字as和多态,如下所示: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没有找到任何进入我item
.detail
.为什么不呢。
然后,我发现这个主题mongoid多态关联错误告诉添加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值放在新行上,结果是相同的。
对于我的第三次尝试,我使用了自定义关系名称,如下所示:
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
但是在午餐撬开贴纸.rb和calendar.rb时,它给了我可怕的消息
DEVEL - Failed to load .../models/sticker.rb; removing partially defined constants
DEVEL - Problem while loading .../models/sticker.rb: uninitialized constant Detail
我再也不知道了..
==> 有人提示吗?
编辑 :
最好有一个等效的Hash[e.attributes]
像这里 在 Ruby 哈希中提取"轻便摩托车::BSON::D ocument"属性,然后这样做:
class Item
include Mongoid::Document
field :detail
end
将我的Picture
、Calendar
和Sticker
保留为类实例(因为我在保存后为每个方法应用不同的方法(。
JG
编辑:替代方式
编辑 08/08/2014,将该部分拆分为该主题的答案。
你应该同时使用具有多态关系的继承给你:
基类
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!
好吧,这在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
如果有人有更好的答案,我接受!
无论如何,希望它能帮助我的下一个。
今天我遇到了类似的问题,我发现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">