Permalink
Browse files

Allowing arrays to be nested in numeric-key hashes

When params was of the form

    {
      :book => {
        :authors_attributes => {
          :'0' => ['William Shakespeare', '52'],
          :'1' => ['Unattributed Assistant']
        }
      }
    }

And its corresponding filter was

    {
      :book => {
        :authors_attributes => {
          :'0' => [],
          :'1' => []
        }
      }
    }

It resulted in params looking like this

    {
      :book => {
        :authors_attributes => {
          :'0' => nil,
          :'1' => nil
        }
      }
    }

This was due to the way hashes with all numeric keys are treated.
I just added a special case when a corresponding filter exists and is an empty
array.
  • Loading branch information...
1 parent a61c8f6 commit ad2c98237b1864b0ddc7f58d4f38d587974a0d02 @simonc simonc committed Mar 26, 2013
Showing with 25 additions and 5 deletions.
  1. +7 −5 lib/action_controller/parameters.rb
  2. +18 −0 test/parameters_permit_test.rb
@@ -168,9 +168,9 @@ def permitted_scalar_filter(params, key)
end
end
- def array_of_permitted_scalars_filter(params, key)
- if has_key?(key) && array_of_permitted_scalars?(self[key])
- params[key] = self[key]
+ def array_of_permitted_scalars_filter(params, key, hash = self)
+ if hash.has_key?(key) && array_of_permitted_scalars?(hash[key])
+ params[key] = hash[key]
end
end
@@ -186,10 +186,12 @@ def hash_filter(params, filter)
array_of_permitted_scalars_filter(params, key)
else
# Declaration {:user => :name} or {:user => [:name, :age, {:adress => ...}]}.
- params[key] = each_element(value) do |element|
+ params[key] = each_element(value) do |element, index|
if element.is_a?(Hash)
element = self.class.new(element) unless element.respond_to?(:permit)
element.permit(*Array.wrap(filter[key]))
+ elsif filter[key].is_a?(Hash) && filter[key][index] == []
+ array_of_permitted_scalars_filter(params, index, value)
end
end
end
@@ -202,7 +204,7 @@ def each_element(value)
# fields_for on an array of records uses numeric hash keys.
elsif value.is_a?(Hash) && value.keys.all? { |k| k =~ /\A-?\d+\z/ }
hash = value.class.new
- value.each { |k,v| hash[k] = yield v }
+ value.each { |k,v| hash[k] = yield(v, k) }
hash
else
yield value
@@ -291,4 +291,22 @@ def assert_filtered_out(params, key)
assert_filtered_out permitted[:book][:authors_attributes]['-1'], :age_of_death
end
+
+ test "fields_for_style_nested_params with nested arrays" do
+ params = ActionController::Parameters.new({
+ :book => {
+ :authors_attributes => {
+ :'0' => ['William Shakespeare', '52'],
+ :'1' => ['Unattributed Assistant']
+ }
+ }
+ })
+ permitted = params.permit :book => { :authors_attributes => { :'0' => [], :'1' => [] } }
+
+ assert_not_nil permitted[:book][:authors_attributes]['0']
+ assert_not_nil permitted[:book][:authors_attributes]['1']
+ assert_nil permitted[:book][:authors_attributes]['2']
+ assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['0'][0]
+ assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['1'][0]
+ end
end

0 comments on commit ad2c982

Please sign in to comment.