From 3650ca983c5c2ffd1a2993fa091bf504594325a7 Mon Sep 17 00:00:00 2001
From: Jahfer Husain <jahfer.husain@shopify.com>
Date: Fri, 7 Jul 2017 13:16:06 -0400
Subject: Add ActiveModel::Errors#merge!

ActiveModel::Errors#merge! allows ActiveModel::Errors to append errors from
a separate ActiveModel::Errors instance onto their own.

Example:

    person = Person.new
    person.errors.add(:name, :blank)

    errors = ActiveModel::Errors.new(Person.new)
    errors.add(:name, :invalid)

    person.errors.merge!(errors)
    puts person.errors.messages
    # => { name: ["can't be blank", "is invalid"] }
---
 activemodel/CHANGELOG.md               |  4 ++++
 activemodel/lib/active_model/errors.rb | 12 ++++++++++++
 activemodel/test/cases/errors_test.rb  | 12 ++++++++++++
 3 files changed, 28 insertions(+)

diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 2916e5eabb..048c43f2c4 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,7 @@
+*   Add method `#merge!` for `ActiveModel::Errors`.
+
+    *Jahfer Husain*
+
 *   Fix regression in numericality validator when comparing Decimal and Float input
     values with more scale than the schema.
 
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 942b4fa9bb..76c23df541 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -93,6 +93,18 @@ module ActiveModel
       @details  = other.details.dup
     end
 
+    # Merges the errors from <tt>other</tt>.
+    #
+    # other - The ActiveModel::Errors instance.
+    #
+    # Examples
+    #
+    #   person.errors.merge!(other)
+    def merge!(other)
+      @messages.merge!(other.messages) { |_, ary1, ary2| ary1 + ary2 }
+      @details.merge!(other.details) { |_, ary1, ary2| ary1 + ary2 }
+    end
+
     # Clear the error messages.
     #
     #   person.errors.full_messages # => ["name cannot be nil"]
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index 43aee5a814..7383b3e9b0 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -375,6 +375,18 @@ class ErrorsTest < ActiveModel::TestCase
     assert_equal [:name], person.errors.details.keys
   end
 
+  test "merge errors" do
+    errors = ActiveModel::Errors.new(Person.new)
+    errors.add(:name, :invalid)
+
+    person = Person.new
+    person.errors.add(:name, :blank)
+    person.errors.merge!(errors)
+
+    assert_equal({ name: ["can't be blank", "is invalid"] }, person.errors.messages)
+    assert_equal({ name: [{ error: :blank }, { error: :invalid }] }, person.errors.details)
+  end
+
   test "errors are marshalable" do
     errors = ActiveModel::Errors.new(Person.new)
     errors.add(:name, :invalid)
-- 
cgit v1.2.3