Ruby on rails 如何将“first”或“initialize”步骤与“-Mongoid”的“accepts”嵌套属性一起使用

Ruby on rails 如何将“first”或“initialize”步骤与“-Mongoid”的“accepts”嵌套属性一起使用,ruby-on-rails,ruby,mongoid,Ruby On Rails,Ruby,Mongoid,我想在模型创建/表单提交过程中加入一个检查现有关系对象的步骤。例如,假设我有一个论文模型,其中有很多作者。在我的CreatePaper表单上,我想为:name设置一个authors\u attributes字段,然后在我的Create方法中,我想首先查找数据库中是否存在该作者;如果是,则将该作者添加到论文作者中,如果不是,则执行初始化新作者的正常作者属性步骤 基本上,我想做如下事情: # override authors_attributes def authors_attributes(att

我想在模型创建/表单提交过程中加入一个检查现有关系对象的步骤。例如,假设我有一个论文模型,其中有很多作者。在我的CreatePaper表单上,我想为:name设置一个authors\u attributes字段,然后在我的Create方法中,我想首先查找数据库中是否存在该作者;如果是,则将该作者添加到论文作者中,如果不是,则执行初始化新作者的正常作者属性步骤

基本上,我想做如下事情:

# override authors_attributes
def authors_attributes(attrs)
  attrs.map!{ |attr| Author.where(attr).first_or_initialize.attributes }
  super(attrs)
end
但这不起作用的原因有很多,因为它会弄乱Mongoid对方法的定义,并且除非已经在模型中注册了id,否则不能在_属性中包含id

我知道处理此类情况的首选方法是使用表单对象,例如,与Virtus一起使用。然而,我有点反对这种模式,因为它需要重复字段定义和验证,至少在我的理解中是这样

有没有一个简单的方法来处理这种行为?我觉得这一定是一种常见的情况,所以我肯定错过了什么…

如果我有一份模型纸:

以及论文中嵌入的模型作者:

我可以在控制台中执行此操作:

>纸张=纸张。createtitle:我的论文

>paper.authors_attributes=[{name:Raviolicode}]


>论文作者=>[

我过去处理这个问题的方法是允许从某种类型的选择列表中选择现有记录,无论是大型参考表的搜索对话框还是较小参考表的选择框。对话框或下拉列表中包含了一种创建新参考的方法,而不是选择现有项目之一

通过这种方法,您可以检测记录是否已经存在或需要创建。它避免了第一次\u或\u初始化的需要,因为用户的意图应该从提交给控制器的内容中明确


但是,当用户不想花时间在列表中查找他们想要的内容时,这种方法会遇到困难。如果出现验证错误,您可以为用户显示一些友好的内容,例如,您是不是想选择[已存在的记录]?这也可能对一些人有所帮助。

我遵循了公认答案的建议,并在accepts\u nested\u attributes\u语句上实现了一个reject\u if-guard,如:

accepts_nested_attributes_for :authors, reject_if: :check_author

def check_author(attrs)
  if existing = Author.where(label: attrs['label']).first
    self.authors << existing
    true
  else
    false
  end
end

这看起来仍然像是一个黑客攻击,但它在Mongoid中也能工作…

谢谢你的回答。我想当我需要查找和添加新作者时,我可以为作者ID和作者属性设置单独的字段,但我不知道这在实际的记录/关联保存过程中会发挥多大作用。我知道而不是像这样做,虽然这是一种黑客,我还没有确认它将与Mongoid一起工作。你的答案是最好的,所以赏金是你的。
class Author
  include Mongoid::Document

  embedded_in :paper, inverse_of: :authors

  field :name, type: String
end
accepts_nested_attributes_for :authors, reject_if: :check_author

def check_author(attrs)
  if existing = Author.where(label: attrs['label']).first
    self.authors << existing
    true
  else
    false
  end
end