提交 b3dfd7d1 编写于 作者: S Sean Griffin

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
上级 88f763b0
......@@ -71,8 +71,8 @@ class Errors
# 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 @@ def generate_message(attribute, type = :invalid, options = {})
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 @@ def normalize_message(attribute, message, options)
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
......
......@@ -427,4 +427,13 @@ def test_no_key
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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册