【问题标题】:Form with nested attributes and has_many :through relationship create new record instead of using existing one具有嵌套属性和 has_many 的表单:通过关系创建新记录而不是使用现有记录
【发布时间】:2016-02-03 14:39:31
【问题描述】:


我尝试做的是一个简单的 Plate 表格,您可以在其中选择您想要的成分。成分的数量和名称可能因天而异。
每次创建一个新盘子时,它都会创建 4 个新选项,其中包含 plate_idingredient_id 以及一个布尔值 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 %>

最后是我的 Plate 控制器:

  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 具有创建的新成分的成分 ID。

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

在 ID=1 的选择中找不到 ID=1 的成分

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

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

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 nested-attributes


    【解决方案1】:

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

    您最好只使用collection_select 选择现有成分作为choice 记录的一部分(即,只需保存成分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 包含的对象中找到了成分 ID,并使用该 ID 访问成分,并检索名称属性。

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

    【讨论】:

    • 感谢您的回答,但如果我删除accepted_nested_parameters_for :ingredient,我将看不到表格中的成分名称。如果我在我的choices_attributes: 中删除ingredient_attributes: [ :name],我创建的选择有空的ingredient_idplate_id,只有布尔值被保存
    • collection_select 将按名称为您提供所有成分的下拉列表,并应显示当前选择的成分(按名称)。当你尝试的时候你没有看到吗?
    • 对不起,我做错了什么...您的回答有效!谢谢 !而不是下拉,是否可以只有一种成分,因为我不想改变它,例如选择两次相同的成分。
    • 是的,您可以只显示成分名称,而不进行任何选择,但是您应该将 ingredient_id 放在隐藏字段中,以确保它在属性哈希中返回。我已经修改了答案以显示一种方法。
    • 完美!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-21
    • 2015-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 2023-01-12
    相关资源
    最近更新 更多