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:
parent
88f763b047
commit
b3dfd7d16c
2 changed files with 32 additions and 2 deletions
|
@ -71,8 +71,8 @@ module ActiveModel
|
||||||
# end
|
# end
|
||||||
def initialize(base)
|
def initialize(base)
|
||||||
@base = base
|
@base = base
|
||||||
@messages = Hash.new { |messages, attribute| messages[attribute] = [] }
|
@messages = apply_default_array({})
|
||||||
@details = Hash.new { |details, attribute| details[attribute] = [] }
|
@details = apply_default_array({})
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize_dup(other) # :nodoc:
|
def initialize_dup(other) # :nodoc:
|
||||||
|
@ -493,6 +493,16 @@ module ActiveModel
|
||||||
I18n.translate(key, options)
|
I18n.translate(key, options)
|
||||||
end
|
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
|
private
|
||||||
def normalize_message(attribute, message, options)
|
def normalize_message(attribute, message, options)
|
||||||
case message
|
case message
|
||||||
|
@ -506,6 +516,17 @@ module ActiveModel
|
||||||
def normalize_detail(message, options)
|
def normalize_detail(message, options)
|
||||||
{ error: message }.merge(options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS))
|
{ error: message }.merge(options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS))
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
# Raised when a validation cannot be corrected by end users and are considered
|
# Raised when a validation cannot be corrected by end users and are considered
|
||||||
|
|
|
@ -427,4 +427,13 @@ class ErrorsTest < ActiveModel::TestCase
|
||||||
assert_equal [:name], person.errors.messages.keys
|
assert_equal [:name], person.errors.messages.keys
|
||||||
assert_equal [:name], person.errors.details.keys
|
assert_equal [:name], person.errors.details.keys
|
||||||
end
|
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
|
end
|
||||||
|
|
Loading…
Reference in a new issue