我已升级到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
如果我尝试使用嵌套Product
创建新的Note
,如下所示:
params = {:name => 'Test', :notes_attributes => {'0' => {'body' => 'Body'}}}
p = Product.new(params)
p.save!
验证失败并显示以下消息:
ActiveRecord::RecordInvalid: Validation failed: Notes product can't be blank
我理解为什么会发生这种情况 - 这是因为validates_presence_of :product_id
类上的Note
,并且因为在保存新记录时,Product
对象没有有一个id
。但是,我不想删除此验证;我认为删除它是不正确的。
我也可以首先手动创建Product
,然后添加Note
来解决问题,但这会破坏accepts_nested_attributes_for
的简单性。
是否有标准的Rails方法在新记录上创建嵌套对象?
答案 0 :(得分:16)
这是一个常见的循环依赖问题。有existing LightHouse ticket值得一试。
我希望在Rails 3中大大改进,但与此同时你必须做一个解决方法。一种解决方案是设置嵌套时设置的虚拟属性,以使验证成为条件。
class Note < ActiveRecord::Base
belongs_to :product
validates_presence_of :product_id, :unless => :nested
attr_accessor :nested
end
然后,您可以将此属性设置为表单中的隐藏字段。
<%= note_form.hidden_field :nested %>
这应该足以在通过嵌套表单创建注释时设置nested
属性。 未测试。
答案 1 :(得分:7)
如果您使用Rails3,请查看此文档。
答案 2 :(得分:3)
Ryan的解决方案实际上非常酷。 我去了,让我的控制器变得更胖,这样就不必在视图中出现这种嵌套了。主要是因为我的观点有时是json,所以我希望能够尽可能少地逃离。
class Product < ActiveRecord::Base
has_many :notes
accepts_nested_attributes_for :note
end
class Note < ActiveRecord::Base
belongs_to :product
validates_presence_of :product_id unless :nested
attr_accessor :nested
end
class ProductController < ApplicationController
def create
if params[:product][:note_attributes]
params[:product][:note_attributes].each { |attribute|
attribute.merge!({:nested => true})
}
end
# all the regular create stuff here
end
end
答案 3 :(得分:0)
最佳解决方案是使用parental_control插件:http://github.com/h-lame/parental_control