使用Mongoid从同一模型中嵌入_many和embeds_one

时间:2011-10-16 09:35:30

标签: ruby-on-rails ruby mongodb mongoid

我有两个模型,博客和主题。博客embeds_many:主题和主题embedded_in:博客。我还有Blog embeds_one:theme(用于激活的主题)。这不起作用。使用blog.themes.create创建主题时,不会存储该主题。如果我改变了集合,那么它们就不会被嵌入,一切正常。

# This does NOT work!
class Blog
  embeds_many :themes
  embeds_one  :theme
end

class Theme
  embedded_in :blog
end

BUT

# This DOES work!
class Blog
  has_many :themes
  has_one  :theme
end

class Theme
  belongs_to :blog
end

任何人都知道这是为什么?

更新

将主题之一分配给(选定)主题也存在问题。

blog.themes = [theme_1, theme_2]
blog.save!

blog.theme = blog.themes.first
blog.save!

blog.reload
blog.theme # returns nil

3 个答案:

答案 0 :(得分:2)

通过这种方法,您可以将相同的文档嵌入两次:一次在主题集合中,然后在选定的主题中。

我建议删除第二个关系并使用字符串属性来存储当前主题名称。你可以这样做:

class Blog
  include Mongoid::Document
  field :current_theme_name, type: String

  embeds_many :themes

  def current_theme
    themes.find_by(name: current_theme_name)
  end
end

class Theme
  include Mongoid::Document
  field :name, type: String

  embedded_in :blog
end

请注意,mongoid embeded文档在主文档的同时进行初始化,并且不需要额外的查询。

答案 1 :(得分:1)

好的,所以我遇到了同样的问题,并认为我偶然发现了解决方案(我正在检查code for the Metadata on relations)。

试试这个:

class Blog
  embeds_many :themes, :as => :themes_collection, :class_name => "Theme"
  embeds_one  :theme, :as => :theme_item, :class_name => "Theme"
end

class Theme
  embedded_in :themes_collection,     :polymorphic => true
  embedded_in :theme_item,     :polymorphic => true
end

我所拥有的辨别猜测:

  • 第一个参数(例如:themes)实际上成为方法名称。
  • :as伪造了实际的关系,因此需要在两个类中匹配。
  • :class_name似乎非常明显,该类用于实际序列化数据。

希望这会有所帮助 - 我显然不是关于mongoid内部工作的专家,但这应该足以让你跑步。我的测试现在是绿色的,数据按预期顺序排列。

答案 2 :(得分:1)

删除embeds_one :theme,然后将其getter和setter方法放在Blog类中:

def theme
  themes.where(active: true).first
end

def theme=(thm)
  theme.set(active: false)
  thm.set(active: true)
end

blog.save!之后无需调用blog.theme = blog.themes.first因为set执行原子操作。

此外,请不要忘记在field :active, type: Boolean, default: false模型中添加Theme

希望这适合你。