我基本上遇到了与这篇文章相同的问题,但我的情况略有不同:has_many nested form with a has_one nested form within it
但正如该帖中提到的其他人所提供的答案并未解决问题。
设置关系,以便Invoice has_many项目和每个Item has_one Modifier。我正在尝试制作一个form_for Invoice,允许用户创建许多项目,每个项目都有一个修饰符。
模型
class Invoice < ActiveRecord::Base
has_many :items
has_many :modifiers, through: :items
accepts_nested_attributes_for :items
end
class Item < ActiveRecord::Base
belongs_to :invoice
belongs_to :modifier
accepts_nested_attributes_for :modifier
end
class Modifier < ActiveRecord::Base
has_one :item
end
CONTROLLER
class Invoice
def new
@invoice = Invoice.new
end
def edit
end
...
end
次(HAML)
invoice.html.haml:
= form_for @invoice do |f|
= f.text_field :status
= f.fields_for :items do |builder|
= render partial: "items/fields", locals: { :f => builder }
= link_to_add_association 'New Item', f, :items, partial: "items/fields", id: "add-item-button"
items/_fields.html.haml:
.nested-fields
- @item = @invoice.items.build
= f.fields_for :modifier, @item.build_modifier do |modifier|
= modifier.text_field :name
让我们回顾一下发生了什么。为了构建嵌套的has_one关系,我在嵌套字段partial中构建了一个Item,以便我可以构建has_one修饰符。这是因为rails要求你在has_one关系中显式调用'build_something'(通常在控制器的new中调用它,但我只想在有人单击New Item按钮时构建)。为了创建新的发票,此代码完美运行。检查控制台,我看到关系已创建,我可以验证是否已成功创建修改器。
然而,当我回去编辑发票时,cocoon知道我已经有了一个修饰符,因此它调用partial一次为我的单个修饰符创建必要的fields_。这些字段是空的。这是有道理的,因为当茧渲染部分时,它正在构建一个带有新修饰符的新代码并将字段设置为空白。我可以确认这是发生了什么,因为一旦我正确地保存了修改器,我可以进入我的部分,删除两个构建调用,并查看编辑页面,正确显示保存的修改器信息就好了。
当然,现在我已经删除了构建调用,表单不再保存我创建的任何修改器。基本上,我需要在那里构建调用来构建新的Modifiers,但如果我想查看它们,我就不能在那里使用它们。
有没有人能解决这种情况?我发现了多个堆栈溢出问题,但没有一个能解决这个问题。
答案 0 :(得分:3)
您说has_one
但是在您的模型中我看到了has_many
?
您嵌套的部分items/_fields
是错误的:您构建了一个额外的项目,并且不需要这样做。 link_to_add_association
中的Coccon构建了一个要插入的新项目。
有两种方法可以做你想做的事。
1)在部分
中要在您的部分中正确处理它,您可以执行以下操作(items/_fields.html.haml
):
.nested-fields
- f.object.build_modifier if f.object.new_record?
= f.fields_for :modifier do |modifier|
= modifier.text_field :name
在rails中,要引用表单的对象,您可以使用f.object
。请注意这将起作用,但我们必须检查它是否是新创建的对象。或者,我们可以检查modifier
是否存在。
2)使用:wrap_object
选项(documentation)
Cocoon允许使用新创建的对象执行一些额外的代码。所以在你的情况下会变成:
= link_to_add_association('New item', f, :items,
:wrap_object => Proc.new { |item| item.build_modifier; item })