diff options
-rw-r--r-- | actionpack/lib/action_controller/metal/strong_parameters.rb | 14 | ||||
-rw-r--r-- | actionpack/test/controller/parameters/parameters_permit_test.rb | 5 |
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" } |