mirror of https://github.com/rails/rails
Support `ActionController::Parameters#deep_merge`
When [rails/rails#20868][] changed the `ActionController::Parameters` ancestory from `HashWithIndifferentAccess` to `Object`, support for `#deep_merge` and `#deep_merge!` were omitted. This commit restores support by integrating with [ActiveSupport::DeepMergeable](./activesupport/lib/active_support/deep_mergeable.rb). [rails/rails#20868]: https://github.com/rails/rails/pull/20868 Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
This commit is contained in:
parent
5fcc61076d
commit
1d999e681e
|
@ -1,3 +1,8 @@
|
||||||
|
* Add support for `#deep_merge` and `#deep_merge!` to
|
||||||
|
`ActionController::Parameters`.
|
||||||
|
|
||||||
|
*Sean Doyle*
|
||||||
|
|
||||||
## Rails 7.1.0.beta1 (September 13, 2023) ##
|
## Rails 7.1.0.beta1 (September 13, 2023) ##
|
||||||
|
|
||||||
* `AbstractController::Translation.raise_on_missing_translations` removed
|
* `AbstractController::Translation.raise_on_missing_translations` removed
|
||||||
|
|
|
@ -4,6 +4,7 @@ require "active_support/core_ext/hash/indifferent_access"
|
||||||
require "active_support/core_ext/array/wrap"
|
require "active_support/core_ext/array/wrap"
|
||||||
require "active_support/core_ext/string/filters"
|
require "active_support/core_ext/string/filters"
|
||||||
require "active_support/core_ext/object/to_query"
|
require "active_support/core_ext/object/to_query"
|
||||||
|
require "active_support/deep_mergeable"
|
||||||
require "action_dispatch/http/upload"
|
require "action_dispatch/http/upload"
|
||||||
require "rack/test"
|
require "rack/test"
|
||||||
require "stringio"
|
require "stringio"
|
||||||
|
@ -137,6 +138,8 @@ module ActionController
|
||||||
# params[:key] # => "value"
|
# params[:key] # => "value"
|
||||||
# params["key"] # => "value"
|
# params["key"] # => "value"
|
||||||
class Parameters
|
class Parameters
|
||||||
|
include ActiveSupport::DeepMergeable
|
||||||
|
|
||||||
cattr_accessor :permit_all_parameters, instance_accessor: false, default: false
|
cattr_accessor :permit_all_parameters, instance_accessor: false, default: false
|
||||||
|
|
||||||
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
|
cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
|
||||||
|
@ -853,13 +856,41 @@ module ActionController
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# :call-seq: merge!(other_hash)
|
||||||
|
#
|
||||||
# Returns the current +ActionController::Parameters+ instance with
|
# Returns the current +ActionController::Parameters+ instance with
|
||||||
# +other_hash+ merged into current hash.
|
# +other_hash+ merged into current hash.
|
||||||
def merge!(other_hash)
|
def merge!(other_hash, &block)
|
||||||
@parameters.merge!(other_hash.to_h)
|
@parameters.merge!(other_hash.to_h, &block)
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# :method: deep_merge
|
||||||
|
# :call-seq: deep_merge(other_hash, &block)
|
||||||
|
#
|
||||||
|
# Returns a new +ActionController::Parameters+ instance with +self+ and +other_hash+ merged recursively.
|
||||||
|
#
|
||||||
|
# Like with +Hash#merge+ in the standard library, a block can be provided
|
||||||
|
# to merge values.
|
||||||
|
#
|
||||||
|
#--
|
||||||
|
# Implemented by ActiveSupport::DeepMergeable#deep_merge.
|
||||||
|
|
||||||
|
##
|
||||||
|
# :method: deep_merge!
|
||||||
|
# :call-seq: deep_merge!(other_hash, &block)
|
||||||
|
#
|
||||||
|
# Same as +#deep_merge+, but modifies +self+.
|
||||||
|
#
|
||||||
|
#--
|
||||||
|
# Implemented by ActiveSupport::DeepMergeable#deep_merge!.
|
||||||
|
|
||||||
|
def deep_merge?(other_hash) # :nodoc
|
||||||
|
other_hash.is_a?(ActiveSupport::DeepMergeable)
|
||||||
|
end
|
||||||
|
|
||||||
# Returns a new +ActionController::Parameters+ instance with all keys
|
# Returns a new +ActionController::Parameters+ instance with all keys
|
||||||
# from current hash merged into +other_hash+.
|
# from current hash merged into +other_hash+.
|
||||||
def reverse_merge(other_hash)
|
def reverse_merge(other_hash)
|
||||||
|
|
|
@ -319,6 +319,62 @@ class ParametersPermitTest < ActiveSupport::TestCase
|
||||||
assert_equal "32", @params[:person][:age]
|
assert_equal "32", @params[:person][:age]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "not permitted is sticky beyond deep merges" do
|
||||||
|
assert_not_predicate @params.deep_merge(a: "b"), :permitted?
|
||||||
|
end
|
||||||
|
|
||||||
|
test "permitted is sticky beyond deep merges" do
|
||||||
|
@params.permit!
|
||||||
|
assert_predicate @params.deep_merge(a: "b"), :permitted?
|
||||||
|
end
|
||||||
|
|
||||||
|
test "not permitted is sticky beyond deep_merge!" do
|
||||||
|
assert_not_predicate @params.deep_merge!(a: "b"), :permitted?
|
||||||
|
end
|
||||||
|
|
||||||
|
test "permitted is sticky beyond deep_merge!" do
|
||||||
|
@params.permit!
|
||||||
|
assert_predicate @params.deep_merge!(a: "b"), :permitted?
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deep_merge with other Hash" do
|
||||||
|
first, last = @params.dig(:person, :name).values_at(:first, :last)
|
||||||
|
merged_params = @params.deep_merge(person: { name: { last: "A." } })
|
||||||
|
|
||||||
|
assert_equal first, merged_params.dig(:person, :name, :first)
|
||||||
|
assert_not_equal last, merged_params.dig(:person, :name, :last)
|
||||||
|
assert_equal "A.", merged_params.dig(:person, :name, :last)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deep_merge! with other Hash" do
|
||||||
|
first, last = @params.dig(:person, :name).values_at(:first, :last)
|
||||||
|
@params.deep_merge!(person: { name: { last: "A." } })
|
||||||
|
|
||||||
|
assert_equal first, @params.dig(:person, :name, :first)
|
||||||
|
assert_not_equal last, @params.dig(:person, :name, :last)
|
||||||
|
assert_equal "A.", @params.dig(:person, :name, :last)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deep_merge with other Parameters" do
|
||||||
|
first, last = @params.dig(:person, :name).values_at(:first, :last)
|
||||||
|
other_params = ActionController::Parameters.new(person: { name: { last: "A." } }).permit!
|
||||||
|
merged_params = @params.deep_merge(other_params)
|
||||||
|
|
||||||
|
assert_equal first, merged_params.dig(:person, :name, :first)
|
||||||
|
assert_not_equal last, merged_params.dig(:person, :name, :last)
|
||||||
|
assert_equal "A.", merged_params.dig(:person, :name, :last)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deep_merge! with other Parameters" do
|
||||||
|
first, last = @params.dig(:person, :name).values_at(:first, :last)
|
||||||
|
other_params = ActionController::Parameters.new(person: { name: { last: "A." } }).permit!
|
||||||
|
@params.deep_merge!(other_params)
|
||||||
|
|
||||||
|
assert_equal first, @params.dig(:person, :name, :first)
|
||||||
|
assert_not_equal last, @params.dig(:person, :name, :last)
|
||||||
|
assert_equal "A.", @params.dig(:person, :name, :last)
|
||||||
|
end
|
||||||
|
|
||||||
test "#reverse_merge with parameters" do
|
test "#reverse_merge with parameters" do
|
||||||
default_params = ActionController::Parameters.new(id: "1234", person: {}).permit!
|
default_params = ActionController::Parameters.new(id: "1234", person: {}).permit!
|
||||||
merged_params = @params.reverse_merge(default_params)
|
merged_params = @params.reverse_merge(default_params)
|
||||||
|
|
Loading…
Reference in New Issue