0

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.

twigonometry
  • 166
  • 1
  • 9
  • 1
    I cannot give you a solution quickly (and I also consider the whole of this a very narrow issue), but you should keep in mind that rails has some "special" behaviour when it generates checkboxes through with the form helpers. That is where the hidden input field comes from. Try to research the `cocoon` gem and how it works internally. It might even give you the feature that you want – kluka Apr 06 '20 at 17:41
  • Thanks for this. It seems that cocoon works similarly to the second method discussed in railscast i.e. with links to helper methods rather than checkboxes. I have implemented this method already within the form and it seems to work (this is the extra code I mentioned in the question) but is there a way of getting the checkboxes to do what I want? If not, I will look into the suggested method as I know that it works – twigonometry Apr 07 '20 at 11:43

2 Answers2

0

This is default Rails behavior as explained on the checkbox documentation page.

zwippie
  • 15,050
  • 3
  • 39
  • 54
0

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
twigonometry
  • 166
  • 1
  • 9