具有嵌套属性和 has_many 的表单:通过关系创建新记录而不是使用现有记录

Form with nested attributes and has_many :through relationship create new record instead of using existing one


我尝试做的是一个简单的 Plate 表格,您可以在其中选择所需的成分。成分的数量和名称可能会因天而异。
每次创建一个新的 Plate 时,它​​都会创建 4 个带有 plate_idingredient_id 的新 Choices 以及一个布尔值 chosen
plate_id 来自新的盘子创建,ingredient_id 应该是我的数据库中已经存在的成分的 ID,chosen 如果成分应该在盘子里。

这是我的 类 盘子、选择和配料:

class Plate < ActiveRecord::Base
    has_many :choices
    has_many :ingredients, through: :choices
    accepts_nested_attributes_for :choices
end

class Choice < ActiveRecord::Base
    belongs_to :plate
    belongs_to :ingredient
    accepts_nested_attributes_for :ingredient
end

class Ingredient < ActiveRecord::Base
    has_many :choices
    has_many :plates, through: :choices
end

我的 Plate 嵌套表单如下所示:

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>

  <%= f.fields_for :choices do |fc| %>
    <%= fc.check_box :chosen %>
    <%= fc.fields_for :ingredient do |fi| %>
        <%= fi.text_field(:name)%> <br />
    <% end %>
  <% end %>

最后是我的平板控制器:

  def new
    @plate = Plate.new
    @choice1 = @plate.choices.build
    @choice2 = @plate.choices.build
    @choice3 = @plate.choices.build
    @choice4 = @plate.choices.build
    @ingredient1 = Ingredient.find_by_name('peach')
    @ingredient2 = Ingredient.find_by_name('banana')
    @ingredient3 = Ingredient.find_by_name('pear')
    @ingredient4 = Ingredient.find_by_name('apple')
    @choice1.ingredient_id = @ingredient1.id
    @choice2.ingredient_id = @ingredient2.id
    @choice3.ingredient_id = @ingredient3.id
    @choice4.ingredient_id = @ingredient4.id

  end

  def plate_params
      params.require(:plate).permit(:name, choices_attributes: [:chosen, ingredient_attributes: [ :name]])
  end

我的问题是,当我创建一个新盘子时,它会创建与所选成分名称相同的新成分(当然 ID 不同),并且 Choices 会创建新成分的 ingredient_id。

我尝试在嵌套属性中添加 :id
params.require(:plate).permit(:name, choices_attributes: [:chosen, ingredient_attributes: [:id, :name]])
但是当我这样做时,我出错了:

Couldn't find Ingredient with ID=1 for Choice with ID=

我搜索了答案但找不到任何答案,我想我对 Rails 参数、表单和嵌套属性的了解不足以理解问题出在哪里。

感谢您的帮助!
ps : 这是我在 Stack Overflow 上的第一个问题,如果我的问题有任何问题请告诉我

您不需要 accepted_nested_parameters_for :ingredient,因为该表单并非旨在让您创建配料或编辑配料。

最好只使用 collection_select 到 select 现有成分作为 choice 记录的一部分(即,只保存 ingredient_id)。

  <%= f.fields_for :choices do |fc| %>
    <%= fc.check_box :chosen %>
    <%= fc.collection_select(:ingredient_id, Ingredient.all, :id, :name, prompt: true) %>
  <% end %>

然后你的属性应该是...

params.require(:plate).permit(:name, choices_attributes: [:chosen, :ingredient_id]) 

如果你只想显示成分但不允许用户更改成分,你可以这样做

  <%= f.fields_for :choices do |fc| %>
    <%= fc.check_box :chosen %>
    <%= fc.hidden_field :ingredient_id %>
    <%= Ingredient.find(fc.object.ingredient_id).name %>
  <% end %>

您在表单对象 fc 包含的对象中找到 ingredient_id 并使用该 ID 访问成分,并检索名称属性。

还要注意 :ingredient_id 的隐藏字段 ... 以确保它在属性散列中返回。