Skip to content

Instantly share code, notes, and snippets.

@abe33
Last active January 2, 2016 19:28
Show Gist options
  • Save abe33/8350113 to your computer and use it in GitHub Desktop.
Save abe33/8350113 to your computer and use it in GitHub Desktop.
nested_form and strong_parameters issues with 2 nested models forms. The customs gem (https://github.com/inkstak/customs) is used to provide basic resource flow in controllers (hence the `resource_params` method)
-# Here resource is the timeline
= simple_nested_form_for resource, url: [resource] do |form|
%table.nested_form
= form.fields_for :marker_sections, wrapper: false do |section_form|
%tr.fields
%td
%table.nested_form
%thead
%tr.section
%th{colspan: 2}= section_form.input :name
= nested_form_remove section_form
%tbody
= section_form.fields_for :markers, wrapper: false do |marker_form|
%tr.fields.marker
%td= marker_form.input :name
%td= marker_form.input :term_at
= nested_form_remove marker_form
= nested_form_add section_form, for: :markers, cols: 3
= nested_form_add form, for: :marker_sections
= default_actions
class Timeline < ActiveRecord::Base
has_many :marker_sections
has_many :markers, through: :marker_sections
accepts_nested_attributes_for :marker_sections, allow_destroy: true
end
class MarkerSection < ActiveRecord::Base
belongs_to :timeline
has_many :markers
validates :name, presence: true
accepts_nested_attributes_for :markers, allow_destroy: true
end
class Marker < ActiveRecord::Base
belongs_to :marker_section
validates :name, :term_at, :marker_section, presence: true
end
# It gives a 'Unpermitted parameters: 1389351190703, new_marker_sections' in console
{"marker_sections_attributes"=>{}}
# This is what the params hash contains prior to sanitization
{
"utf8"=>"✓",
"authenticity_token"=>"*******",
"timeline"=> {
"marker_sections_attributes"=>{
"1389351190703"=>{
"name"=>"Foo",
"_destroy"=>"false"
},
"new_marker_sections"=>{
"markers_attributes"=>{
"1389351191802"=>{
"name"=>"Bar",
"term_at(3i)"=>"10",
"term_at(2i)"=>"1",
"term_at(1i)"=>"2014",
"_destroy"=>"false"
}
}
}
}
},
"id"=>"5"
}
class TimelinesController < ApplicationController
load_and_authorize_resource
def resource_params
if params[:timeline].present?
timeline_params = params.require(:timeline).permit(
:id,
marker_sections_attributes: [
:_destroy,
:id,
:name,
:timeline_id,
markers_attributes: [
:_destroy,
:id,
:name,
:marker_section_id,
:term_at
]
]
)
timeline_params
else
nil
end
end
end
@lcoq
Copy link

lcoq commented Jan 10, 2014

Everything looks good to me, maybe the parameters sent looks a little weird ( for example the marker_sections_attributes is a hash. I guessed it should be an array. And the new_marker_sections looks to be an id ? I did not know this kind of attrs).

Anyway, I've found a pretty good article that may help you on that work, if you did not already found it : http://createdbypete.com/articles/working-with-nested-forms-and-a-many-to-many-association-in-rails-4/

@abe33
Copy link
Author

abe33 commented Jan 10, 2014

Thanks Louis, the article's example and my situation is quite different, the questions instances already exist when the form is generated, which mean that they already have an id and an index in the survey.questions array.

Here's what I discovered about nested_form (as for version 0.3.2):

  1. If I have no sections at all, and if I only create one section and submit the form, the parameters look like:

      {"timeline"=>{"marker_sections_attributes"=>{"1389360179189"=>{"name"=>"Foo", "_destroy"=>"false"}}}}
    

    The record is saved properly.

  2. If I have no sections at all, and I create a section and a marker for that section, the parameters looks like:

    {"timeline"=>{
       "marker_sections_attributes"=>{
          "1389360211342"=>{
            "name"=>"Foo", 
            "_destroy"=>"false"
          }, 
          "new_marker_sections"=>{
            "markers_attributes"=>{
              "1389360218312"=>{
                "name"=>"Bar", 
                "term_at(3i)"=>"10", 
                "term_at(2i)"=>"1", 
                "term_at(1i)"=>"2014", 
                "_destroy"=>"false"
              }
            }
          }
        }
      }
    }
    

    Note the new_marker_sections parameter, it seems like it hold attributes of nested models of a to create model. But if I try creating two sections with one marker for each, parameters looks like:

    {
      "timeline"=>{
        "marker_sections_attributes"=>{
          "1389360577960"=>{
            "name"=>"Foo", 
            "_destroy"=>"false"
          }, 
         "new_marker_sections"=>{
           "markers_attributes"=>{
             "1389360580623"=>{
               "marker_section_id"=>"1389360577960", 
               "name"=>"Bar", 
               "term_at(3i)"=>"10", 
               "term_at(2i)"=>"1", 
               "term_at(1i)"=>"2014", 
               "_destroy"=>"false"
             }, 
             "1389360588767"=>{
               "name"=>"Bar 2", 
               "term_at(3i)"=>"10", 
               "term_at(2i)"=>"1", 
               "term_at(1i)"=>"2014", 
               "_destroy"=>"false"
             }
           }
         },
         "1389360582782"=>{
           "name"=>"Foo 2", 
           "_destroy"=>"false"
          }
        }
      }
    }
    

    As you can see here, when we could expect to have one new_marker_sections attribute for each new section there's only one for the first marker_sections_attributes entry.

    In both cases the records aren't saved.

  3. If I already have a section (like after step #1), and I add a marker for this section, the parameters looks like:

    {
      "timeline"=>{
        "marker_sections_attributes"=>{
          "0"=>{
            "name"=>"Foo", 
            "_destroy"=>"false", 
            "id"=>"18"
          }, 
         "null"=>{
           "markers_attributes"=>{
             "1389361405773"=>{
               "name"=>"Bar", 
               "term_at(3i)"=>"10", 
               "term_at(2i)"=>"1", 
               "term_at(1i)"=>"2014", 
               "_destroy"=>"false"
             }
           }
         }
       }
    }
    }
    

    Where did come the null key? Of course the marker record isn't saved properly. It goes worse if I had more than one marker or if I also create new section at the same time.

As it is, I must conclude that nested_form is completely unusable. Sad thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment