Rails _destroy 字段在表单中出现两次
Rails _destroy field appearing twice in form
我有两个模型,Preset 和 Plot,如下:
class Preset < ApplicationRecord
belongs_to :user
has_many :plots, :dependent => :destroy
accepts_nested_attributes_for :plots, allow_destroy: true
end
class Plot < ApplicationRecord
belongs_to :preset
belongs_to :theme, optional: true
end
以及用于编辑预设的嵌套表单:
= form_with(model: @preset, local: true, method: "patch") do |f|
= label_tag(:preset_name, "Preset name:")
= text_field_tag(:preset_name, @preset.name)
%br
= f.fields_for :plots do |builder|
%br
= render 'editplot', f: builder
%br
根据 railscast 196:
定义用于销毁绘图的复选框的部分 _editplot
= f.label(:name, "Change plot:")
= f.select(:name, options_for_select([['Existing Plot 1', 'Existing Plot 1'], ['Existing Plot 2', 'Existing Plot 2']]))
= f.label(:_destroy, "Remove plot")
= f.check_box(:_destroy)
我在预设控制器中允许使用 _destroy 参数
def preset_params
params.require(:preset).permit(:name, plots_attributes: [:id, :name, :parameter_path, :theme_id, :_destroy])
end
编辑预设的所有其他方面工作正常,但 _destroy 的复选框没有。编辑界面销毁两个地块之一的参数在控制台显示如下:
Parameters: {"authenticity_token"=>"TOKEN", "preset_name"=>"Preset", "preset"=>{"plots_attributes"=>{"0"=>{"name"=>"Existing Plot 1", "_destroy"=>"1", "id"=>"16"}, "1"=>{"name"=>"Existing Plot 1", "_destroy"=>"0", "id"=>"17"}}}, "commit"=>"Update Preset", "id"=>"25"}
“_destroy”=>“1”的存在表明这是按预期工作的。然而,当使用 Chrome 开发工具检查页面时,它显示复选框旁边还有一个隐藏字段 <input name="preset[plots_attributes][0][_destroy]" type="hidden" value="0">
,提交表单时也传递了其 _destroy 值 0。我有一种感觉,这个元素正在干扰表单,但我不确定它来自哪里或如何摆脱它。
我没有在这里包含它,但我有一些相同形式的 JS 代码可以添加和删除 'new plot' 部分,这些代码会生成自己的 _destroy 字段。我不认为它们会是问题的原因,但如有必要,我可以在编辑中添加此代码。
这是默认 Rails 行为,如 checkbox documentation page 中所述。
正如 zwippie 指出的那样,问题不在于复选框,而在于我的控制器。我试图在控制器内手动更新预设和绘图的属性(即使用像 @plot.update(name: plot_name, parameter_path: _parameter_path)
这样的行)。因为我是手动执行此操作,所以我实际上并没有处理 _destroy 参数,因此 rails 一旦它从表单传递过来就没有对它做任何事情。
为了解决这个问题,我使用了 @preset.update(preset_params)
,其中 preset_params
表示控制器中允许的参数。只要允许 _destroy,它就会删除对象。
def preset_params
params.require(:preset).permit(:name, plots_attributes: [:id, :name, :parameter_path, :theme_id, :_destroy])
end
我有两个模型,Preset 和 Plot,如下:
class Preset < ApplicationRecord
belongs_to :user
has_many :plots, :dependent => :destroy
accepts_nested_attributes_for :plots, allow_destroy: true
end
class Plot < ApplicationRecord
belongs_to :preset
belongs_to :theme, optional: true
end
以及用于编辑预设的嵌套表单:
= form_with(model: @preset, local: true, method: "patch") do |f|
= label_tag(:preset_name, "Preset name:")
= text_field_tag(:preset_name, @preset.name)
%br
= f.fields_for :plots do |builder|
%br
= render 'editplot', f: builder
%br
根据 railscast 196:
定义用于销毁绘图的复选框的部分 _editplot= f.label(:name, "Change plot:")
= f.select(:name, options_for_select([['Existing Plot 1', 'Existing Plot 1'], ['Existing Plot 2', 'Existing Plot 2']]))
= f.label(:_destroy, "Remove plot")
= f.check_box(:_destroy)
我在预设控制器中允许使用 _destroy 参数
def preset_params
params.require(:preset).permit(:name, plots_attributes: [:id, :name, :parameter_path, :theme_id, :_destroy])
end
编辑预设的所有其他方面工作正常,但 _destroy 的复选框没有。编辑界面销毁两个地块之一的参数在控制台显示如下:
Parameters: {"authenticity_token"=>"TOKEN", "preset_name"=>"Preset", "preset"=>{"plots_attributes"=>{"0"=>{"name"=>"Existing Plot 1", "_destroy"=>"1", "id"=>"16"}, "1"=>{"name"=>"Existing Plot 1", "_destroy"=>"0", "id"=>"17"}}}, "commit"=>"Update Preset", "id"=>"25"}
“_destroy”=>“1”的存在表明这是按预期工作的。然而,当使用 Chrome 开发工具检查页面时,它显示复选框旁边还有一个隐藏字段 <input name="preset[plots_attributes][0][_destroy]" type="hidden" value="0">
,提交表单时也传递了其 _destroy 值 0。我有一种感觉,这个元素正在干扰表单,但我不确定它来自哪里或如何摆脱它。
我没有在这里包含它,但我有一些相同形式的 JS 代码可以添加和删除 'new plot' 部分,这些代码会生成自己的 _destroy 字段。我不认为它们会是问题的原因,但如有必要,我可以在编辑中添加此代码。
这是默认 Rails 行为,如 checkbox documentation page 中所述。
正如 zwippie 指出的那样,问题不在于复选框,而在于我的控制器。我试图在控制器内手动更新预设和绘图的属性(即使用像 @plot.update(name: plot_name, parameter_path: _parameter_path)
这样的行)。因为我是手动执行此操作,所以我实际上并没有处理 _destroy 参数,因此 rails 一旦它从表单传递过来就没有对它做任何事情。
为了解决这个问题,我使用了 @preset.update(preset_params)
,其中 preset_params
表示控制器中允许的参数。只要允许 _destroy,它就会删除对象。
def preset_params
params.require(:preset).permit(:name, plots_attributes: [:id, :name, :parameter_path, :theme_id, :_destroy])
end