ruby-on-railsruby-on-rails-4strong-parameters

Rails 4 Strong Params with multiple objects and integer keys


I'm submitting a form with 2-4 objects at once, depending on how many the parent has. I realize that this is probably unconventional, but I really wanted the user to be able to edit all of the objects at once on one form. On my form, I'm doing:

<%= simple_fields_for "derps[]", derp do |f| %>

<% end %>

Then I'm doing this in the controller:

def update
  @derps = []
  @rejects = []
  derps_params.each do |key, hash|
    derp = Derp.find(key)
    derp.assign_attributes(hash)
    @rejects << derp unless derp.save
  end
  if @rejects.empty?
    redirect_to @parent, flash: {success: 'Derps were successfully updated.'}
  else
    @derps = @rejects
    render :edit
  end
end

Lets say there are two objects - the params are coming through as:

"derps"=>{"1"=>{"attribute"=>"39", "another_attribute"=>"serp", "a_third_attribute"=>"yerp"}, "2"=>{"attribute"=>"30", "another_attribute"=>"49", }}

I had this working in Rails 3 without strong params. I'm upgrading to rails 4 and I'm struggling with how to get this working - I keep getting "Unpermitted parameters: 1, 2"

I'm assuming I need to do something like:

def mashes_params
  params.require(:derps).permit(
  id: []

or

def mashes_params
  params.require(:derps).permit(
  :id, 

Something along those lines, but I've tried it every way I can think of without luck.

Any ideas here?


Solution

  • Final Edit (hopefully):

    Had to rethink this from the ground up. I came to the conclusion: Since :id works as a wildcard, but is not allowed as the key of the hash, why not always make the keys 1-4, so I can whitelist them explicitly, then get the ID from a key-value in the hash, much like is done in traditional form nesting? Thats how I ended up solving it. Here's the final implementation that I have working:

    <% i = @parent.derps.index(derp) + 1 %>
    <%= simple_fields_for "derps[#{i}]", derp do |f| %>
      <%= f.hidden_field :id, value: derp.id %>
      <%= render "rest_of_the_fields" %>
    <% end %>
    

    Then in the controller:

    def update
      @derps = []
      @rejects = []
      derp_params.each do |key, hash|
        derp = Derp.find(hash.delete("id"))
        derp.assign_attributes(hash)
        @rejects << derp unless derp.save
      end
      if @rejects.empty?
        redirect_to @parent, flash: {success: "Derps updated successfully."} 
      else
        @derps = @rejects
        render :edit
      end
    end
    

    Then here are the strong params:

    def derp_params
      p = [:id, :attribute_1, :another_attribute, ...]
      params.require(:derps).permit(
        "1" => p, "2" => p, "3" => p, "4" => p
      )
    end
    

    Phew. Hope this helps someone.