diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 696e6d31dada14af850b649036bd42e1c8f60e19..6f2c8c1c530bf886013a5f8a0fa7978d5972f743 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -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 diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb index fbf208836f1d143ea754afff4448358d1304bcfa..c90ee7021cf9e1b0185f72656868fe6948b5401f 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -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