I have two models, Preset and Plot, as below:
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
And a nested form for editing presets:
= 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
A partial _editplot that defines the checkbox for destroying the plot, as per railscast 196:
= 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)
I have allowed the _destroy parameter in the presets controller
def preset_params
params.require(:preset).permit(:name, plots_attributes: [:id, :name, :parameter_path, :theme_id, :_destroy])
end
All other aspects of editing the presets work fine, but the checkbox for _destroy does not. The parameters for destroying one of two plots on the edit screen are displayed in console as follows:
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"}
The presence of "_destroy"=>"1" suggests this is working as intended. However, when inspecting the page with Chrome Dev tools it shows there is also a hidden field <input name="preset[plots_attributes][0][_destroy]" type="hidden" value="0">
alongside the checkbox, whose _destroy value of 0 is also passed when the form is submitted. I have a feeling that this element is interfering with the form, but I'm not sure where it's come from or how to get rid of it.
I haven't included it here, but I have some JS code in the same form that adds and removes 'new plot' partials, and these generate their own _destroy fields. I didn't think they would be the cause of the issue, but I can add this code in an edit if necessary.
The issue was not with the checkbox, as pointed out by zwippie, but with my controller. I was trying to update the attributes of the preset and plots manually within the controller (i.e. using lines like @plot.update(name: plot_name, parameter_path: _parameter_path)
). Because I was doing this manually, I wasn't actually handling the _destroy parameter and therefore rails wasn't doing anything with it once it had been passed from the form.
To fix this, I used @preset.update(preset_params)
instead, where preset_params
represents the permitted parameters within the controller. As long as _destroy is permitted, it deletes the object.
def preset_params
params.require(:preset).permit(:name, plots_attributes: [:id, :name, :parameter_path, :theme_id, :_destroy])
end