mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Only dup Ruby's Hash and Array.
When calling `to_h` on an `ActionController::Parameters` instance it would `deep_dup` its internal parameters. This inadvertently called `dup` on a passed Active Record model which would create new models. Fix by only dupping Ruby's Arrays and Hashes.
This commit is contained in:
parent
623c3706b9
commit
4b46c5ce83
2 changed files with 46 additions and 2 deletions
|
@ -1,4 +1,5 @@
|
|||
require 'active_support/core_ext/hash/indifferent_access'
|
||||
require 'active_support/core_ext/hash/transform_values'
|
||||
require 'active_support/core_ext/array/wrap'
|
||||
require 'active_support/core_ext/string/filters'
|
||||
require 'active_support/rescuable'
|
||||
|
@ -175,7 +176,7 @@ module ActionController
|
|||
# safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
|
||||
def to_h
|
||||
if permitted?
|
||||
@parameters.deep_dup
|
||||
convert_parameters_to_hashes(@parameters)
|
||||
else
|
||||
slice(*self.class.always_permitted_parameters).permit!.to_h
|
||||
end
|
||||
|
@ -185,7 +186,7 @@ module ActionController
|
|||
# <tt>ActiveSupport::HashWithIndifferentAccess</tt> representation of this
|
||||
# parameter.
|
||||
def to_unsafe_h
|
||||
@parameters.deep_dup
|
||||
convert_parameters_to_hashes(@parameters)
|
||||
end
|
||||
alias_method :to_unsafe_hash, :to_unsafe_h
|
||||
|
||||
|
@ -594,6 +595,21 @@ module ActionController
|
|||
end
|
||||
end
|
||||
|
||||
def convert_parameters_to_hashes(value)
|
||||
case value
|
||||
when Array
|
||||
value.map { |v| convert_parameters_to_hashes(v) }
|
||||
when Hash
|
||||
value.transform_values do |v|
|
||||
convert_parameters_to_hashes(v)
|
||||
end.with_indifferent_access
|
||||
when Parameters
|
||||
value.to_h
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
def convert_hashes_to_parameters(key, value)
|
||||
converted = convert_value_to_parameters(value)
|
||||
@parameters[key] = converted unless converted.equal?(value)
|
||||
|
|
|
@ -297,4 +297,32 @@ class ParametersPermitTest < ActiveSupport::TestCase
|
|||
assert @params.to_h.is_a? ActiveSupport::HashWithIndifferentAccess
|
||||
assert_not @params.to_h.is_a? ActionController::Parameters
|
||||
end
|
||||
|
||||
test "to_h only deep dups Ruby collections" do
|
||||
company = Class.new do
|
||||
attr_reader :dupped
|
||||
def dup; @dupped = true; end
|
||||
end.new
|
||||
|
||||
params = ActionController::Parameters.new(prem: { likes: %i( dancing ) })
|
||||
assert_equal({ 'prem' => { 'likes' => %i( dancing ) } }, params.permit!.to_h)
|
||||
|
||||
params = ActionController::Parameters.new(companies: [ company, :acme ])
|
||||
assert_equal({ 'companies' => [ company, :acme ] }, params.permit!.to_h)
|
||||
assert_not company.dupped
|
||||
end
|
||||
|
||||
test "to_unsafe_h only deep dups Ruby collections" do
|
||||
company = Class.new do
|
||||
attr_reader :dupped
|
||||
def dup; @dupped = true; end
|
||||
end.new
|
||||
|
||||
params = ActionController::Parameters.new(prem: { likes: %i( dancing ) })
|
||||
assert_equal({ 'prem' => { 'likes' => %i( dancing ) } }, params.to_unsafe_h)
|
||||
|
||||
params = ActionController::Parameters.new(companies: [ company, :acme ])
|
||||
assert_equal({ 'companies' => [ company, :acme ] }, params.to_unsafe_h)
|
||||
assert_not company.dupped
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue