具有嵌套属性和 has_many 的表单:通过关系创建新记录而不是使用现有记录
Form with nested attributes and has_many :through relationship create new record instead of using existing one
我尝试做的是一个简单的 Plate 表格,您可以在其中选择所需的成分。成分的数量和名称可能会因天而异。
每次创建一个新的 Plate 时,它都会创建 4 个带有 plate_id
和 ingredient_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
的隐藏字段 ... 以确保它在属性散列中返回。
我尝试做的是一个简单的 Plate 表格,您可以在其中选择所需的成分。成分的数量和名称可能会因天而异。
每次创建一个新的 Plate 时,它都会创建 4 个带有 plate_id
和 ingredient_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
的隐藏字段 ... 以确保它在属性散列中返回。