如何使用accepts_nested_attributes_for创建嵌套对象

pet*_*rjm 22 ruby-on-rails

我已升级到Rails 2.3.3(从2.1.x开始),我正试图找出accepts_nested_attributes_for方法.我可以使用该方法更新现有的嵌套对象,但我无法使用它来创建新的嵌套对象.鉴于人为的例子:

class Product < ActiveRecord::Base
  has_many :notes
  accepts_nested_attributes_for :notes
end

class Note < ActiveRecord::Base
  belongs_to :product
  validates_presence_of :product_id, :body
end
Run Code Online (Sandbox Code Playgroud)

如果我尝试Product使用嵌套创建一个新的,Note如下所示:

params = {:name => 'Test', :notes_attributes => {'0' => {'body' => 'Body'}}}
p = Product.new(params)
p.save!
Run Code Online (Sandbox Code Playgroud)

它使用以下消息验证失败:

ActiveRecord::RecordInvalid: Validation failed: Notes product can't be blank
Run Code Online (Sandbox Code Playgroud)

我明白为什么会这样 - 这是因为validates_presence_of :product_idNote课堂上,并且因为在保存新记录时,该Product对象没有id.但是,我不想删除此验证; 我认为删除它是不正确的.

我也可以通过手动创建第Product一个,然后添加Note,但这会破坏简单性来解决问题accepts_nested_attributes_for.

是否有标准的Rails方法在新记录上创建嵌套对象?

rya*_*anb 16

这是一个常见的循环依赖问题.有一个现有的灯塔票,这是值得一试.

我希望在Rails 3中有很大的改进,但与此同时你必须做一个解决方法.一种解决方案是设置嵌套时设置的虚拟属性,以使验证成为条件.

class Note < ActiveRecord::Base
  belongs_to :product
  validates_presence_of :product_id, :unless => :nested
  attr_accessor :nested
end
Run Code Online (Sandbox Code Playgroud)

然后,您将此属性设置为表单中的隐藏字段.

<%= note_form.hidden_field :nested %>
Run Code Online (Sandbox Code Playgroud)

这应该足以在nested通过嵌套表单创建注释时设置属性.未经测试.

  • 在Rails 3中,通过添加:has_many,has_one和belongs_to的inverse_of选项解决了这个问题.参见例如http://www.daokaous.com/rails3.0.0_doc/classes/ActiveRecord/Associations/ClassMethods.html#M001988"双向关联"部分 (11认同)
  • 我在Rails 3中遇到过这个问题,有关如何解决它的任何更新? (4认同)
  • 当记录的父亲还不存在时,inverse_of似乎不起作用,因此不能测试id.看起来这个嵌套黑客是唯一的方法.:( (3认同)
  • 我在以下情况下选择禁用验证:id == nil.因为这应该只在写一个新的嵌套记录时发生,我希望这是安全的.奇怪的是这个问题一直到2.3.8. (2认同)

kub*_*oon 7

如果您使用Rails3,请检查此文档.

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#label-Validating+the+presence+of+a+parent+model

  • 非常重要的一点是你应该验证"产品"的存在而不是"product_id" (2认同)