From 61e50814040d68c640b16afd2b9c419d2f12fad6 Mon Sep 17 00:00:00 2001
From: Vokhmin Alexey V <avokhmin@gmail.com>
Date: Thu, 3 Dec 2015 21:18:57 +0300
Subject: `ActiveRecord::Base#becomes` should copy the errors

---
 activemodel/lib/active_model/errors.rb        | 12 ++++++++++++
 activemodel/test/cases/errors_test.rb         | 10 ++++++++++
 activerecord/lib/active_record/persistence.rb |  2 +-
 activerecord/test/cases/persistence_test.rb   | 21 ++++++++++++++++++++-
 4 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 4726a68f69..ef6141a51d 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -81,6 +81,18 @@ module ActiveModel
       super
     end
 
+    # Copies the errors from <tt>other</tt>.
+    #
+    # other - The ActiveModel::Errors instance.
+    #
+    # Examples
+    #
+    #   person.errors.copy!(other)
+    def copy!(other) # :nodoc:
+      @messages = other.messages.dup
+      @details  = other.details.dup
+    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 f6d171bec6..a5ac055033 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -410,4 +410,14 @@ class ErrorsTest < ActiveModel::TestCase
     person.errors.clear
     assert person.errors.details.empty?
   end
+
+  test "copy errors" do
+    errors = ActiveModel::Errors.new(Person.new)
+    errors.add(:name, :invalid)
+    person = Person.new
+    person.errors.copy!(errors)
+
+    assert_equal [:name], person.errors.messages.keys
+    assert_equal [:name], person.errors.details.keys
+  end
 end
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 9e566031b8..522c35252f 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -215,7 +215,7 @@ module ActiveRecord
       became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
       became.instance_variable_set("@new_record", new_record?)
       became.instance_variable_set("@destroyed", destroyed?)
-      became.instance_variable_set("@errors", errors)
+      became.errors.copy!(errors)
       became
     end
 
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index b2e59e3970..af15e63d9c 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -19,6 +19,8 @@ require 'models/person'
 require 'models/pet'
 require 'models/ship'
 require 'models/toy'
+require 'models/admin'
+require 'models/admin/user'
 require 'rexml/document'
 
 class PersistenceTest < ActiveRecord::TestCase
@@ -161,7 +163,24 @@ class PersistenceTest < ActiveRecord::TestCase
     assert !company.valid?
     original_errors = company.errors
     client = company.becomes(Client)
-    assert_equal original_errors, client.errors
+    assert_equal original_errors.keys, client.errors.keys
+  end
+
+  def test_becomes_errors_base
+    child_class = Class.new(Admin::User) do
+      store_accessor :settings, :foo
+
+      def self.name; 'Admin::ChildUser'; end
+    end
+
+    admin = Admin::User.new
+    admin.errors.add :token, :invalid
+    child = admin.becomes(child_class)
+
+    assert_equal [:token], child.errors.keys
+    assert_nothing_raised do
+      child.errors.add :foo, :invalid
+    end
   end
 
   def test_dupd_becomes_persists_changes_from_the_original
-- 
cgit v1.2.3