From 4d7986283653ff4fbd5a82dd273ed9795a0c6a65 Mon Sep 17 00:00:00 2001
From: Edouard CHIN <edouard.chin@shopify.com>
Date: Thu, 9 Mar 2017 01:42:16 -0500
Subject: Added `reverse_merge`/`reverse_merge!` to AC::Parameters:

- This PR adds the `reverse_merge` and `reverse_merge!` method to `ActionController::Parameters`
- Fixes #28353
---
 actionpack/CHANGELOG.md                            |  4 +++
 .../action_controller/metal/strong_parameters.rb   | 15 +++++++++++
 .../parameters/parameters_permit_test.rb           | 29 ++++++++++++++++++++++
 3 files changed, 48 insertions(+)

(limited to 'actionpack')

diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 38132371cc..4b45e95124 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,7 @@
+*   Added `#reverse_merge` and `#reverse_merge!` methods to `ActionController::Parameters`
+
+    *Edouard Chin*
+
 *   Fix malformed URLS when using `ApplicationController.renderer`
 
     The Rack environment variable `rack.url_scheme` was not being set so `scheme` was
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 9690f0ca28..0217376ab3 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -660,6 +660,21 @@ module ActionController
       self
     end
 
+    # Returns a new <tt>ActionController::Parameters</tt> with all keys from
+    # current hash merged into +other_hash+.
+    def reverse_merge(other_hash)
+      new_instance_with_inherited_permitted_status(
+        other_hash.to_h.merge(@parameters)
+      )
+    end
+
+    # Returns current <tt>ActionController::Parameters</tt> instance with
+    # current hash merged into +other_hash+.
+    def reverse_merge!(other_hash)
+      @parameters.merge!(other_hash.to_h) { |key, left, right| left }
+      self
+    end
+
     # This is required by ActiveModel attribute assignment, so that user can
     # pass +Parameters+ to a mass assignment methods in a model. It should not
     # matter as we are using +HashWithIndifferentAccess+ internally.
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index 8920914af1..b51c55b1f1 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -302,6 +302,35 @@ class ParametersPermitTest < ActiveSupport::TestCase
     assert_equal "32", @params[:person][:age]
   end
 
+  test "#reverse_merge with parameters" do
+    default_params = ActionController::Parameters.new(id: "1234", person: {}).permit!
+    merged_params = @params.reverse_merge(default_params)
+
+    assert_equal "1234", merged_params[:id]
+    refute_predicate merged_params[:person], :empty?
+  end
+
+  test "not permitted is sticky beyond reverse_merge!" do
+    merged_params = @params.reverse_merge(a: "b")
+
+    refute_predicate @params, :permitted?
+  end
+
+  test "permitted is sticky beyond reverse_merge!" do
+    @params.permit!
+    merged_params = @params.reverse_merge(a: "b")
+
+    assert_predicate @params, :permitted?
+  end
+
+  test "#reverse_merge! with parameters" do
+    default_params = ActionController::Parameters.new(id: "1234", person: {}).permit!
+    @params.reverse_merge!(default_params)
+
+    assert_equal "1234", @params[:id]
+    refute_predicate @params[:person], :empty?
+  end
+
   test "modifying the parameters" do
     @params[:person][:hometown] = "Chicago"
     @params[:person][:family] = { brother: "Jonas" }
-- 
cgit v1.2.3