aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb14
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb5
2 files changed, 17 insertions, 2 deletions
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 1c06d9a7db..41be1b121e 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -3,6 +3,7 @@ require 'active_support/core_ext/array/wrap'
require 'active_support/rescuable'
require 'action_dispatch/http/upload'
require 'stringio'
+require 'set'
module ActionController
# Raised when a required parameter is missing.
@@ -125,6 +126,13 @@ module ActionController
@permitted = self.class.permit_all_parameters
end
+ # Attribute that keeps track of converted arrays, if any, to avoid double
+ # looping in the common use case permit + mass-assignment. Defined in a
+ # method to instantiate it only if needed.
+ def converted_arrays
+ @converted_arrays ||= Set.new
+ end
+
# Returns +true+ if the parameter is permitted, +false+ otherwise.
#
# params = ActionController::Parameters.new
@@ -329,8 +337,10 @@ module ActionController
end
def convert_value_to_parameters(value)
- if value.is_a?(Array)
- value.map { |_| convert_value_to_parameters(_) }
+ if value.is_a?(Array) && !converted_arrays.member?(value)
+ converted = value.map { |_| convert_value_to_parameters(_) }
+ converted_arrays << converted
+ converted
elsif value.is_a?(Parameters) || !value.is_a?(Hash)
value
else
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index ba191a7227..9c1828e9aa 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -160,6 +160,11 @@ class ParametersPermitTest < ActiveSupport::TestCase
end
end
+ test 'arrays are converted at most once' do
+ params = ActionController::Parameters.new(foo: [{}])
+ assert params[:foo].equal?(params[:foo])
+ end
+
test "fetch doesnt raise ParameterMissing exception if there is a default" do
assert_equal "monkey", @params.fetch(:foo, "monkey")
assert_equal "monkey", @params.fetch(:foo) { "monkey" }