1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Ensure that instances of ActiveModel::Errors can be marshalled

We now use default procs inside of the errors object, which gets
included by default when marshaling anything that includes
`ActiveModel::Validations`. This means that Active Record objects cannot
be marshalled. We strip and apply the default proc ourselves. This will
ensure the objects are YAML serializable as well, since YAML falls back
to marshal implementations now. This is less important, however, as the
errors aren't included when dumping Active Record objects.

This commit does not include a changelog entry, as 5.0 is still in RC
status at the time of writing, and 5.0.0 will not release with the bug
this fixes.

Fixes #25165
This commit is contained in:
Sean Griffin 2016-05-30 14:00:14 -04:00
parent 88f763b047
commit b3dfd7d16c
2 changed files with 32 additions and 2 deletions

View file

@ -71,8 +71,8 @@ module ActiveModel
# end
def initialize(base)
@base = base
@messages = Hash.new { |messages, attribute| messages[attribute] = [] }
@details = Hash.new { |details, attribute| details[attribute] = [] }
@messages = apply_default_array({})
@details = apply_default_array({})
end
def initialize_dup(other) # :nodoc:
@ -493,6 +493,16 @@ module ActiveModel
I18n.translate(key, options)
end
def marshal_dump
[@base, without_default_proc(@messages), without_default_proc(@details)]
end
def marshal_load(array)
@base, @messages, @details = array
apply_default_array(@messages)
apply_default_array(@details)
end
private
def normalize_message(attribute, message, options)
case message
@ -506,6 +516,17 @@ module ActiveModel
def normalize_detail(message, options)
{ error: message }.merge(options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS))
end
def without_default_proc(hash)
hash.dup.tap do |new_h|
new_h.default_proc = nil
end
end
def apply_default_array(hash)
hash.default_proc = proc { |h, key| h[key] = [] }
hash
end
end
# Raised when a validation cannot be corrected by end users and are considered

View file

@ -427,4 +427,13 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal [:name], person.errors.messages.keys
assert_equal [:name], person.errors.details.keys
end
test "errors are marshalable" do
errors = ActiveModel::Errors.new(Person.new)
errors.add(:name, :invalid)
serialized = Marshal.load(Marshal.dump(errors))
assert_equal errors.messages, serialized.messages
assert_equal errors.details, serialized.details
end
end