在 mongoid 中保存 embeds_many

Posted

技术标签:

【中文标题】在 mongoid 中保存 embeds_many【英文标题】:saving embeds_many in mongoid 【发布时间】:2012-10-02 19:20:58 【问题描述】:

我有一个 embeds_many 关联,当我保存父文档时,没有保存子文档。

class User
  include Mongoid::Document

  embeds_many :user_missions
  attr_accessible :user_missions_attributes
  accepts_nested_attributes_for :user_missions, allow_destroy: true
end

class UserMission
  include Mongoid::Document

  embedded_in :user, :inverse_of => :user_missions

  has_one :mission, autosave: true
  validates_presence_of :mission

  attr_accessible :mission_title

  def mission_title
    mission.try(:title)
  end

  def mission_title=(title)
    self.mission = Mission.find_or_create_by(:title => title) if title.present?
  end
end

这是我失败的规范:

it "should save mission to user_mission when created" do
  user_mission = UserMission.new
  user = create(:user)
  user.user_missions << user_mission
  user_mission.mission_title = "Created Title"

  user.save!
  #user_mission.save!

  User.first.user_missions[0].mission.title.should == "Created Title"
end

我明白了:

undefined method `title' for nil:NilClass

当我在#user_mission.save! 行中发表评论时,它起作用了。问题是我需要它在表单中工作,我认为 Mongoid 会自动保存嵌入文档的字段。

如何获取父 User 文档来保存嵌入的 UserMission 的数据?

谢谢

更新

这是我忘记添加的任务模型(不确定是否重要):

class Mission
  include Mongoid::Document

  belongs_to :user_mission, :inverse_of => :mission

  attr_accessible :title
  field :title, type: String
  validates_presence_of :title

  field :lowercase_title
  before_create :lower_title_case

  field :description, type: String

private
  def lower_title_case
    self.lowercase_title = self.title.downcase
  end
end

【问题讨论】:

【参考方案1】:

AFAIK,嵌入式文档不能有引用关系。所以对embedded_inhas_one 的调用是矛盾的。

除此之外,您是否尝试过重新排序测试中的行,以便首先创建用户,然后通过用户创建user_misison

user = create(:user)
user_mission = user.user_missions.new
user_mission.mission_title = "Created Title"

user.save!

看起来您正在尝试执行的操作类似于 SQL JOIN 表。如果这是您想要实现的目标,那么最好利用 Mongoid 令人敬畏的 N-N 引用映射(除非您需要在“加入”集合中存储额外的数据)。我会做类似的事情:

class User
  include Mongoid::Document
  has_and_belongs_to_many :missions
end

class Mission
  include Mongoid::Document
  has_and_belongs_to_many :users
end

如果您想通过用户创建任务,请在关系的任务端打开自动保存。

编辑:看到您的任务模型后,我意识到您正试图直接从您的任务模型中直接引用嵌入文档 UserMission (belongs_to :user_mission)。就像我之前说的,不可行。您需要***文档、用户和任务之间的某种关系。您可以通过将该行更改为:

has_many :users

然后将 has_one :mission 从 User 模型更改为:

belongs_to :mission

但您将无法从用户端使用自动保存。

编辑:更正了正确的方式来展示从用户到任务的 1-n 关系的正确方式。

【讨论】:

我确实创建了“join”表来存储我稍后将添加的额外信息(例如创建时间)。此外,用户 embeds_many UserMissions 和 UserMissions 是在用户中嵌入的。还有一个我忘记包含的模型,称为 Mission,UserMission 与之有 has_one 关系(我现在将在更新中添加它。)我刚刚尝试重新排序,但没有成功。 在看到任务课程后编辑。 另外,请确保您在测试中创建了一个 Mission 实例。最后一行需要更改为User.first.mission.title.should == "Created Title",而不是通过user_mission。我建议编写一个单独的测试以确保正确设置 user_mission 的标题。 删除任务中的belongs_to 并将user_mission 中的has_one :mission, autosave: true 更改为belongs_to :mission, :inverse_of =&gt; nil 有效。谢谢。如果我想查找具有特定任务的所有 UserMissions,您是否建议我使用参考文档而不是嵌入文档? 是的,您需要为此使用参考文档。或者,如果您设置了用户和任务之间的关系,您可以简单地查询与特定任务相关的用户,然后枚举他们以提取嵌入的 user_mission。

以上是关于在 mongoid 中保存 embeds_many的主要内容,如果未能解决你的问题,请参考以下文章

使用 mongoid 在 rails 中保存带有嵌入对象/文档的对象

Backbone.js 和嵌入式一对多关联

管理 mongoid 迁移

使用factorygirls模型embeds_many和embedded_in关系

在 Mongoid 中检索 id 数组

在 Mongoid 中更新模型模式