Permalink
Browse files

Fix ActiveModel::Errors#dup

Since ActiveModel::Errors instance keeps all error messages as hash
we should duplicate this object as well.

Previously ActiveModel::Errors was a subclass of ActiveSupport::OrderedHash,
which results in different behavior on dup, this may result in regression for
people relying on it.

Because Rails 3.2 stills supports Ruby 1.8.7 in order to properly fix this
regression we need to backport #initialize_dup.
  • Loading branch information...
1 parent f34e5a7 commit 5da6b6ed672cead5ece53ecab248fe3fdcc3503a @pkondzior pkondzior committed with drogus Jan 17, 2012
Showing with 22 additions and 1 deletion.
  1. +14 −1 activemodel/lib/active_model/errors.rb
  2. +8 −0 activemodel/test/cases/errors_test.rb
@@ -79,6 +79,19 @@ def initialize(base)
@messages = ActiveSupport::OrderedHash.new
end
+ def initialize_dup(other)
+ @messages = other.messages.dup
+ end
+
+ # Backport dup from 1.9 so that #initialize_dup gets called
+ unless Object.respond_to?(:initialize_dup)
+ def dup # :nodoc:
+ copy = super
+ copy.initialize_dup(self)
+ copy
+ end
+ end
+
# Clear the messages
def clear
messages.clear
@@ -118,7 +131,7 @@ def [](attribute)
# p.errors[:name] = "must be set"
# p.errors[:name] # => ['must be set']
def []=(attribute, error)
- self[attribute.to_sym] << error
+ self[attribute] << error
end
# Iterates through each error key, value pair in the error messages hash.
@@ -40,6 +40,14 @@ def test_include?
assert errors.include?(:foo), 'errors should include :foo'
end
+ def test_dup
+ errors = ActiveModel::Errors.new(self)
+ errors[:foo] = 'bar'
+ errors_dup = errors.dup
+ errors_dup[:bar] = 'omg'
+ assert_not_same errors_dup.messages, errors.messages
+ end
+
test "should return true if no errors" do
person = Person.new
person.errors[:foo]

0 comments on commit 5da6b6e

Please sign in to comment.