ruby-on-railsstrong-parametersform-with

Rails permitted parameter not showing up in console


I have a pair of models, Preset and 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

And a nested form for editing presets and their respective plots

= form_with(model: @preset, local: true, method: "patch") do |f|
  = label_tag(:name, "Preset name:")
  = text_field_tag(:name, @preset.name)
  %br
  = f.fields_for :plots do |builder|
    %br
    = render 'editplot', f: builder

And an _editplot partial (this is working correctly, but included for completeness)

= 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 permitted the parameters I need in the presets controller as follows:

private
        def preset_params
            params.require(:preset).permit(:name, plots_attributes: [:id, :name, :parameter_path, :theme_id, :_destroy])
        end

I would therefore expect the :name parameter to be included in preset_params.

The update method in the controller is as follows:

def update
        @preset = Preset.find(params[:id])

        puts "name"
        puts params[:name]

        puts "preset params"
        puts preset_params

        if @preset.update(preset_params)
            redirect_to presets_path, notice: 'Preset was successfully updated.'
            return
        else
            render :edit
            return
        end

When I submit the form, checked plots are deleted as expected. However, the name of the preset itself is not updated. The console shows the parameters include the :name parameter, and its value is correct, but it does not show up in the console when I output preset_params. Where has it gone?

Parameters: {"authenticity_token"=>"15RgDM+SCwfScbQXcHmVGfzo2w8qe972QPdkf/OB9AFeyvtUXdxJpaVGKgCMoLaISYljclmOuIowqrfGyy/Dug==", "name"=>"Edited name", "preset"=>{"plots_attributes"=>{"0"=>{"name"=>"Existing Plot 1", "_destroy"=>"0", "id"=>"3"}, "1"=>{"name"=>"Existing Plot 1", "_destroy"=>"0", "id"=>"4"}}}, "commit"=>"Update Preset", "id"=>"1"}

{"plots_attributes"=><ActionController::Parameters {"0"=><ActionController::Parameters {"id"=>"3", "name"=>"Existing Plot 1", "_destroy"=>"0"} permitted: true>, "1"=><ActionController::Parameters {"id"=>"4", "name"=>"Existing Plot 1", "_destroy"=>"0"} permitted: true>} permitted: true>}

Solution

  • "name" is not inside the "preset" hash in your parameters, see:

    Parameters: {
      "name"=>"Edited name", 
      "preset"=>{
        "plots_attributes"=>{
          "0"=>{
            "name"=>"Existing Plot 1", 
            "_destroy"=>"0", 
            "id"=>"3"
          }, 
          "1"=>{
            "name"=>"Existing Plot 1", 
            "_destroy"=>"0", 
            "id"=>"4"
          }
        }
      }, 
      "commit"=>"Update Preset", 
      "id"=>"1"
    }
    

    So, preset_params is not going to include "name".

    You can try:

    = text_field_tag('preset[name]', @preset.name)
    

    ...to get the name nested in the preset hash.