Skip to content

Instantly share code, notes, and snippets.

@bloudermilk
Created June 6, 2012 21:32
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bloudermilk/2884947 to your computer and use it in GitHub Desktop.
Save bloudermilk/2884947 to your computer and use it in GitHub Desktop.
Convert integer-keyed Hash parameters to Arrays in Rails

Fix for strong_parameters when using accepts_nested_attributes_for

The following before filter looks for any Hash parameters where all the keys are integers and turns them into Arrays. It searches recursively to allow the used of nested attributes within nested attributes. This is necessary to circumvent a bug in the strong_parameters gem which was reported in April 2012. Given params like:

{
  "person" => {
    "dogs_attributes" => {
      "0" => {
        "name" => "Fido"
      },
      "1" => {
        "name" => "Rocket"
      }
    }
  }
}

It will modify them to look like:

{
  "person" => {
    "dogs_attributes" => [
      {
        "name" => "Fido"
      },
      {
        "name" => "Rocket"
      }
    ]
  }
}

How to use

Simply copy the before_filter macro and repair_nested_params method below into your application controller.

class ApplicationController < ActionController::Base
before_filter :repair_nested_params
protected
# Fixes nested attribute params for strong_parameters (turns string keyed hash
# into array of hashes)
def repair_nested_params(obj = params)
obj.each do |key, value|
if value.is_a? Hash
# If any non-integer keys
if value.keys.find {|k, _| k =~ /\D/ }
repair_nested_params(value)
else
obj[key] = value.values
value.values.each {|h| repair_nested_params(h) }
end
end
end
end
end
@mbriggs
Copy link

mbriggs commented Nov 28, 2012

don't know if anyone cares at this point, but if you have a hash that needs to be fixed inside another hash that needs to be fixed (ie. two levels of nested attributes), this doesn't fix the inner level. changing line 16 to obj[key].each {|h| repair_nested_params(h) } fixes it

@FlowerWrong
Copy link

For rails 5

  def repair_nested_params(obj)
    obj.each do |key, value|
      if value.is_a? ActionController::Parameters || value.is_a? Hash
        # If any non-integer keys
        if value.keys.find {|k, _| k =~ /\D/ }
          repair_nested_params(value)
        else
          obj[key] = value.values
          value.values.each {|h| repair_nested_params(h) }
        end
      end
    end
  end

@bloudermilk
Copy link
Author

TFW when the first google result is an answer you posted to your own question years ago

@anthony-bernardo
Copy link

this really work ?

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