1

我基本上遇到了与这篇文章相同的问题,尽管我的情况略有不同:has_many 嵌套表单,其中包含 has_one 嵌套表单

但正如该帖子中的其他人所提到的,提供的答案并不能解决问题。

建立关系以便 Invoice has_many items 和每个 Item has_one 修饰符。我正在尝试制作一个 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

控制器

class Invoice
  def new
    @invoice = Invoice.new
  end

  def edit
  end

  ...
end

意见(哈姆尔)

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 关系,我在嵌套字段部分中构建了一个项目,以便我可以构建 has_one 修饰符。这是因为 rails 要求您在 has_one 关系中显式调用“build_something”(通常这在控制器的 new 中调用,但我只想在有人单击“新建项目”按钮后进行构建)。对于创建新发票,此代码完美运行。检查控制台,我看到关系已创建,我可以验证修饰符是否已成功创建。

但是,当我回去编辑发票时,cocoon 知道我已经有一个修饰符,所以它调用部分一次来为我的单个修饰符创建必要的字段。这些字段为空。不过这是有道理的,因为 cocoon 正在渲染该部分,它正在构建一个带有新修饰符的新代码并将字段设置为空白。我可以确认这是正在发生的事情,因为一旦我正确保存了我的修改器,我就可以进入我的部分,删除两个构建调用,并查看正确显示保存的修改器信息的编辑页面。

当然,现在我已经删除了构建调用,表单不再保存我创建的任何修饰符。所以本质上,我需要那里的构建调用来构建新的修饰符,但如果我想查看它们,我不能把它们放在那里。

有没有人有解决这种情况的方法?我发现了多个堆栈溢出问题,但没有一个能解决这个问题。

4

1 回答 1

3

你说has_one,但在你的模型中我看到了has_many吗?

您嵌套的部分items/_fields是错误的:您构建了一个额外的项目,并且不需要这样做。Coccon,在link_to_add_association构建一个新项目以插入。

有两种方法可以做你想做的事。

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选项(文档

Cocoon 允许使用新创建的对象执行一些额外的代码。所以在你的情况下,这将变成:

= link_to_add_association('New item', f, :items,
        :wrap_object => Proc.new { |item| item.build_modifier; item })
于 2014-11-01T10:00:18.810 回答