如何使用accepts_nested_attributes_for创建嵌套对象

时间:2009-07-30 20:36:31

标签: 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

如果我尝试使用嵌套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方法在新记录上创建嵌套对象?

4 个答案:

答案 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)

答案 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