【问题标题】:real polymorphism in embed relations in mongoidmongoid 中嵌入关系中的实多态性
【发布时间】:2013-11-27 17:15:47
【问题描述】:

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

我有一个类Item,它必须embed_one 包含我的信息的对象。 交易是:
- 我的对象的类型可以是其中之一:CalendarStickerPicture;
- 无论我的对象是什么类型,我都想通过一个唯一的“键”来访问它:detail
例如:

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

首先,我尝试使用关键字 aspolymorphic,如下所述: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 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  

我没有更多的想法..
==> 有人给点建议吗?

编辑
有一个等价于Hash[e.attributes] 就像这里的Extract `Moped::BSON::Document` attributes in Ruby hash 然后这样做会很好:

class Item
    include Mongoid::Document
    field :detail
end  

将我的PictureCalendarSticker 保留为类实例(因为我有不同的方法可以在保存后应用)。

JG

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

【问题讨论】:

  • 这个问题真的很糟糕,我认为你应该对这篇文章有所了解。您应该添加您所做的“编辑”作为答案。
  • @JúlioTurollaRibeiro,完成。感谢您的建议!

标签: ruby mongoid polymorphic-associations


【解决方案1】:

你应该使用继承和多态关系 给你:

基类

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!

【讨论】:

  • 我还没有测试。但是您提出的建议非常接近我在编辑之前提到的测试(Ctrl+F“我最后一次尝试是使用继承”)。当然它解决了开始的错误消息,但它是否给你你真正查询的内容?我的意思是,p.media 肯定会给你Resource 而不是Photo
  • 起初它是嵌入的,所以查询是不同的。但是如果我在控制台中执行 p = Post.last 然后 p.media - 它会将 Photo 对象打印到控制台
  • 打印什么 p.media.class.to_s ?在我的例子中,它也返回了所有的信息,但是类名是错误的
  • 它为我返回照片。我正在使用 mongodb 3.0
【解决方案2】:

嗯,在 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

如果有人有更好的答案,我会接受!
但是,希望它对我的情况有所帮助。

【讨论】:

    【解决方案3】:

    今天遇到了类似的问题,发现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">
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 2011-11-29
      • 1970-01-01
      • 2014-01-31
      相关资源
      最近更新 更多