diff options
Diffstat (limited to 'activemodel')
-rw-r--r-- | activemodel/lib/active_model.rb | 1 | ||||
-rw-r--r-- | activemodel/lib/active_model/error.rb | 95 | ||||
-rw-r--r-- | activemodel/lib/active_model/errors.rb | 84 | ||||
-rw-r--r-- | activemodel/lib/active_model/railtie.rb | 2 | ||||
-rw-r--r-- | activemodel/test/cases/errors_test.rb | 49 | ||||
-rw-r--r-- | activemodel/test/cases/railtie_test.rb | 6 | ||||
-rw-r--r-- | activemodel/test/cases/validations/i18n_validation_test.rb | 99 |
7 files changed, 203 insertions, 133 deletions
diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index c9140dc582..756473e38d 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -53,6 +53,7 @@ module ActiveModel eager_autoload do autoload :Errors + autoload :Error autoload :RangeError, "active_model/errors" autoload :StrictValidationFailed, "active_model/errors" autoload :UnknownAttributeError, "active_model/errors" diff --git a/activemodel/lib/active_model/error.rb b/activemodel/lib/active_model/error.rb index f7267fc7bf..6deab3578d 100644 --- a/activemodel/lib/active_model/error.rb +++ b/activemodel/lib/active_model/error.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "active_support/core_ext/class/attribute" + module ActiveModel # == Active \Model \Error # @@ -8,6 +10,89 @@ module ActiveModel CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict] MESSAGE_OPTIONS = [:message] + class_attribute :i18n_customize_full_message, default: false + + def self.full_message(attribute, message, base_class) # :nodoc: + return message if attribute == :base + attribute = attribute.to_s + + if i18n_customize_full_message && base_class.respond_to?(:i18n_scope) + attribute = attribute.remove(/\[\d\]/) + parts = attribute.split(".") + attribute_name = parts.pop + namespace = parts.join("/") unless parts.empty? + attributes_scope = "#{base_class.i18n_scope}.errors.models" + + if namespace + defaults = base_class.lookup_ancestors.map do |klass| + [ + :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.attributes.#{attribute_name}.format", + :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.format", + ] + end + else + defaults = base_class.lookup_ancestors.map do |klass| + [ + :"#{attributes_scope}.#{klass.model_name.i18n_key}.attributes.#{attribute_name}.format", + :"#{attributes_scope}.#{klass.model_name.i18n_key}.format", + ] + end + end + + defaults.flatten! + else + defaults = [] + end + + defaults << :"errors.format" + defaults << "%{attribute} %{message}" + + attr_name = attribute.tr(".", "_").humanize + attr_name = base_class.human_attribute_name(attribute, default: attr_name) + + I18n.t(defaults.shift, + default: defaults, + attribute: attr_name, + message: message) + end + + def self.generate_message(attribute, type, base, options) # :nodoc: + type = options.delete(:message) if options[:message].is_a?(Symbol) + value = (attribute != :base ? base.send(:read_attribute_for_validation, attribute) : nil) + + options = { + model: base.model_name.human, + attribute: base.class.human_attribute_name(attribute), + value: value, + object: base + }.merge!(options) + + if base.class.respond_to?(:i18n_scope) + i18n_scope = base.class.i18n_scope.to_s + defaults = base.class.lookup_ancestors.flat_map do |klass| + [ :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}", + :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ] + end + defaults << :"#{i18n_scope}.errors.messages.#{type}" + + catch(:exception) do + translation = I18n.translate(defaults.first, options.merge(default: defaults.drop(1), throw: true)) + return translation unless translation.nil? + end unless options[:message] + else + defaults = [] + end + + defaults << :"errors.attributes.#{attribute}.#{type}" + defaults << :"errors.messages.#{type}" + + key = defaults.shift + defaults = options.delete(:message) if options[:message] + options[:default] = defaults + + I18n.translate(key, options) + end + def initialize(base, attribute, type = :invalid, **options) @base = base @attribute = attribute @@ -28,7 +113,7 @@ module ActiveModel def message case raw_type when Symbol - base.errors.generate_message(attribute, raw_type, options.except(*CALLBACKS_OPTIONS)) + self.class.generate_message(attribute, raw_type, @base, options.except(*CALLBACKS_OPTIONS)) else raw_type end @@ -39,7 +124,7 @@ module ActiveModel end def full_message - base.errors.full_message(attribute, message) + self.class.full_message(attribute, message, @base.class) end # See if error matches provided +attribute+, +type+ and +options+. @@ -58,9 +143,9 @@ module ActiveModel end def strict_match?(attribute, type, **options) - return false unless match?(attribute, type, **options) + return false unless match?(attribute, type) - full_message == Error.new(@base, attribute, type, **options).full_message + options == @options.except(*CALLBACKS_OPTIONS + MESSAGE_OPTIONS) end def ==(other) @@ -74,7 +159,7 @@ module ActiveModel protected def attributes_for_hash - [@base, @attribute, @raw_type, @options] + [@base, @attribute, @raw_type, @options.except(*CALLBACKS_OPTIONS)] end end end diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index 3de999308b..22839bd9fb 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -69,11 +69,6 @@ module ActiveModel LEGACY_ATTRIBUTES = [:messages, :details].freeze - class << self - attr_accessor :i18n_customize_full_message # :nodoc: - end - self.i18n_customize_full_message = false - attr_reader :errors alias :objects :errors @@ -198,7 +193,7 @@ module ActiveModel matches.each do |error| @errors.delete(error) end - matches.map(&:message) + matches.map(&:message).presence end # When passed a symbol or a name of a method, returns an array of errors @@ -467,47 +462,7 @@ module ActiveModel # # person.errors.full_message(:name, 'is invalid') # => "Name is invalid" def full_message(attribute, message) - return message if attribute == :base - attribute = attribute.to_s - - if self.class.i18n_customize_full_message && @base.class.respond_to?(:i18n_scope) - attribute = attribute.remove(/\[\d\]/) - parts = attribute.split(".") - attribute_name = parts.pop - namespace = parts.join("/") unless parts.empty? - attributes_scope = "#{@base.class.i18n_scope}.errors.models" - - if namespace - defaults = @base.class.lookup_ancestors.map do |klass| - [ - :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.attributes.#{attribute_name}.format", - :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.format", - ] - end - else - defaults = @base.class.lookup_ancestors.map do |klass| - [ - :"#{attributes_scope}.#{klass.model_name.i18n_key}.attributes.#{attribute_name}.format", - :"#{attributes_scope}.#{klass.model_name.i18n_key}.format", - ] - end - end - - defaults.flatten! - else - defaults = [] - end - - defaults << :"errors.format" - defaults << "%{attribute} %{message}" - - attr_name = attribute.tr(".", "_").humanize - attr_name = @base.class.human_attribute_name(attribute, default: attr_name) - - I18n.t(defaults.shift, - default: defaults, - attribute: attr_name, - message: message) + Error.full_message(attribute, message, @base.class) end # Translates an error message in its default scope @@ -535,40 +490,7 @@ module ActiveModel # * <tt>errors.attributes.title.blank</tt> # * <tt>errors.messages.blank</tt> def generate_message(attribute, type = :invalid, options = {}) - type = options.delete(:message) if options[:message].is_a?(Symbol) - value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil) - - options = { - model: @base.model_name.human, - attribute: @base.class.human_attribute_name(attribute), - value: value, - object: @base - }.merge!(options) - - if @base.class.respond_to?(:i18n_scope) - i18n_scope = @base.class.i18n_scope.to_s - defaults = @base.class.lookup_ancestors.flat_map do |klass| - [ :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}", - :"#{i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ] - end - defaults << :"#{i18n_scope}.errors.messages.#{type}" - - catch(:exception) do - translation = I18n.translate(defaults.first, options.merge(default: defaults.drop(1), throw: true)) - return translation unless translation.nil? - end unless options[:message] - else - defaults = [] - end - - defaults << :"errors.attributes.#{attribute}.#{type}" - defaults << :"errors.messages.#{type}" - - key = defaults.shift - defaults = options.delete(:message) if options[:message] - options[:default] = defaults - - I18n.translate(key, options) + Error.generate_message(attribute, type, @base, options) end def marshal_load(array) # :nodoc: diff --git a/activemodel/lib/active_model/railtie.rb b/activemodel/lib/active_model/railtie.rb index eb7901c7e9..65e20b9791 100644 --- a/activemodel/lib/active_model/railtie.rb +++ b/activemodel/lib/active_model/railtie.rb @@ -14,7 +14,7 @@ module ActiveModel end initializer "active_model.i18n_customize_full_message" do - ActiveModel::Errors.i18n_customize_full_message = config.active_model.delete(:i18n_customize_full_message) || false + ActiveModel::Error.i18n_customize_full_message = config.active_model.delete(:i18n_customize_full_message) || false end end end diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb index baaf404f2e..d66d6ceff0 100644 --- a/activemodel/test/cases/errors_test.rb +++ b/activemodel/test/cases/errors_test.rb @@ -274,6 +274,28 @@ class ErrorsTest < ActiveModel::TestCase assert_equal [msg], person.errors[:name] end + test "added? when attribute was added through a collection" do + person = Person.new + person.errors.add(:"family_members.name", :too_long, count: 25) + assert person.errors.added?(:"family_members.name", :too_long, count: 25) + assert_not person.errors.added?(:"family_members.name", :too_long) + assert_not person.errors.added?(:"family_members.name", :too_long, name: "hello") + end + + test "added? ignores callback option" do + person = Person.new + + person.errors.add(:name, :too_long, if: -> { true }) + assert person.errors.added?(:name, :too_long) + end + + test "added? ignores message option" do + person = Person.new + + person.errors.add(:name, :too_long, message: proc { "foo" }) + assert person.errors.added?(:name, :too_long) + end + test "added? detects indifferent if a specific error was added to the object" do person = Person.new person.errors.add(:name, "cannot be blank") @@ -460,6 +482,27 @@ class ErrorsTest < ActiveModel::TestCase assert_nil person.errors.as_json.default_proc end + test "full_messages doesn't require the base object to respond to `:errors" do + model = Class.new do + def initialize + @errors = ActiveModel::Errors.new(self) + @errors.add(:name, "bar") + end + + def self.human_attribute_name(attr, options = {}) + "foo" + end + + def call + error_wrapper = Struct.new(:model_errors) + + error_wrapper.new(@errors) + end + end + + assert_equal(["foo bar"], model.new.call.model_errors.full_messages) + end + test "full_messages creates a list of error messages with the attribute name included" do person = Person.new person.errors.add(:name, "cannot be blank") @@ -573,6 +616,12 @@ class ErrorsTest < ActiveModel::TestCase assert_not_equal errors_dup.details, errors.details end + test "delete returns nil when no errors were deleted" do + errors = ActiveModel::Errors.new(Person.new) + + assert_nil(errors.delete(:name)) + end + test "delete removes details on given attribute" do errors = ActiveModel::Errors.new(Person.new) errors.add(:name, :invalid) diff --git a/activemodel/test/cases/railtie_test.rb b/activemodel/test/cases/railtie_test.rb index 95ee7cace3..f5ff1a3fd7 100644 --- a/activemodel/test/cases/railtie_test.rb +++ b/activemodel/test/cases/railtie_test.rb @@ -35,20 +35,20 @@ class RailtieTest < ActiveModel::TestCase test "i18n customize full message defaults to false" do @app.initialize! - assert_equal false, ActiveModel::Errors.i18n_customize_full_message + assert_equal false, ActiveModel::Error.i18n_customize_full_message end test "i18n customize full message can be disabled" do @app.config.active_model.i18n_customize_full_message = false @app.initialize! - assert_equal false, ActiveModel::Errors.i18n_customize_full_message + assert_equal false, ActiveModel::Error.i18n_customize_full_message end test "i18n customize full message can be enabled" do @app.config.active_model.i18n_customize_full_message = true @app.initialize! - assert_equal true, ActiveModel::Errors.i18n_customize_full_message + assert_equal true, ActiveModel::Error.i18n_customize_full_message end end diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index b7ee50832c..c81649f493 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -13,8 +13,8 @@ class I18nValidationTest < ActiveModel::TestCase I18n.backend = I18n::Backend::Simple.new I18n.backend.store_translations("en", errors: { messages: { custom: nil } }) - @original_i18n_customize_full_message = ActiveModel::Errors.i18n_customize_full_message - ActiveModel::Errors.i18n_customize_full_message = true + @original_i18n_customize_full_message = ActiveModel::Error.i18n_customize_full_message + ActiveModel::Error.i18n_customize_full_message = true end def teardown @@ -24,7 +24,7 @@ class I18nValidationTest < ActiveModel::TestCase I18n.load_path.replace @old_load_path I18n.backend = @old_backend I18n.backend.reload! - ActiveModel::Errors.i18n_customize_full_message = @original_i18n_customize_full_message + ActiveModel::Error.i18n_customize_full_message = @original_i18n_customize_full_message end def test_full_message_encoding @@ -49,7 +49,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_full_messages_doesnt_use_attribute_format_without_config - ActiveModel::Errors.i18n_customize_full_message = false + ActiveModel::Error.i18n_customize_full_message = false I18n.backend.store_translations("en", activemodel: { errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } }) @@ -59,8 +59,21 @@ class I18nValidationTest < ActiveModel::TestCase assert_equal "Name test cannot be blank", person.errors.full_message(:name_test, "cannot be blank") end + def test_errors_full_messages_on_nested_error_uses_attribute_format + ActiveModel::Error.i18n_customize_full_message = true + I18n.backend.store_translations("en", activemodel: { + errors: { models: { person: { attributes: { gender: "Gender" } } } }, + attributes: { "person/contacts": { gender: "Gender" } } + }) + + person = person_class.new + error = ActiveModel::Error.new(person, :gender, "can't be blank") + person.errors.import(error, attribute: "person[0].contacts.gender") + assert_equal ["Gender can't be blank"], person.errors.full_messages + end + def test_errors_full_messages_uses_attribute_format - ActiveModel::Errors.i18n_customize_full_message = true + ActiveModel::Error.i18n_customize_full_message = true I18n.backend.store_translations("en", activemodel: { errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } }) @@ -71,7 +84,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_full_messages_uses_model_format - ActiveModel::Errors.i18n_customize_full_message = true + ActiveModel::Error.i18n_customize_full_message = true I18n.backend.store_translations("en", activemodel: { errors: { models: { person: { format: "%{message}" } } } }) @@ -82,7 +95,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_full_messages_uses_deeply_nested_model_attributes_format - ActiveModel::Errors.i18n_customize_full_message = true + ActiveModel::Error.i18n_customize_full_message = true I18n.backend.store_translations("en", activemodel: { errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } }) @@ -93,7 +106,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_full_messages_uses_deeply_nested_model_model_format - ActiveModel::Errors.i18n_customize_full_message = true + ActiveModel::Error.i18n_customize_full_message = true I18n.backend.store_translations("en", activemodel: { errors: { models: { 'person/contacts/addresses': { format: "%{message}" } } } }) @@ -104,7 +117,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_attributes_format - ActiveModel::Errors.i18n_customize_full_message = true + ActiveModel::Error.i18n_customize_full_message = true I18n.backend.store_translations("en", activemodel: { errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } }) @@ -115,7 +128,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_model_format - ActiveModel::Errors.i18n_customize_full_message = true + ActiveModel::Error.i18n_customize_full_message = true I18n.backend.store_translations("en", activemodel: { errors: { models: { 'person/contacts/addresses': { format: "%{message}" } } } }) @@ -126,7 +139,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_i18n_attribute_name - ActiveModel::Errors.i18n_customize_full_message = true + ActiveModel::Error.i18n_customize_full_message = true I18n.backend.store_translations("en", activemodel: { attributes: { 'person/contacts/addresses': { country: "Country" } } @@ -138,7 +151,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_full_messages_with_indexed_deeply_nested_attributes_without_i18n_config - ActiveModel::Errors.i18n_customize_full_message = false + ActiveModel::Error.i18n_customize_full_message = false I18n.backend.store_translations("en", activemodel: { errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } }) @@ -149,7 +162,7 @@ class I18nValidationTest < ActiveModel::TestCase end def test_errors_full_messages_with_i18n_attribute_name_without_i18n_config - ActiveModel::Errors.i18n_customize_full_message = false + ActiveModel::Error.i18n_customize_full_message = false I18n.backend.store_translations("en", activemodel: { attributes: { 'person/contacts[0]/addresses[0]': { country: "Country" } } @@ -178,8 +191,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_confirmation_of on generated message #{name}" do person_class.validates_confirmation_of :title, validation_options @person.title_confirmation = "foo" - call = [:title_confirmation, :confirmation, generate_message_options.merge(attribute: "Title")] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title_confirmation, :confirmation, @person, generate_message_options.merge(attribute: "Title")] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -189,8 +202,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_acceptance_of on generated message #{name}" do person_class.validates_acceptance_of :title, validation_options.merge(allow_nil: false) - call = [:title, :accepted, generate_message_options] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :accepted, @person, generate_message_options] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -200,8 +213,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_presence_of on generated message #{name}" do person_class.validates_presence_of :title, validation_options - call = [:title, :blank, generate_message_options] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :blank, @person, generate_message_options] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -211,8 +224,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_length_of for :within on generated message when too short #{name}" do person_class.validates_length_of :title, validation_options.merge(within: 3..5) - call = [:title, :too_short, generate_message_options.merge(count: 3)] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :too_short, @person, generate_message_options.merge(count: 3)] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -223,8 +236,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_length_of for :too_long generated message #{name}" do person_class.validates_length_of :title, validation_options.merge(within: 3..5) @person.title = "this title is too long" - call = [:title, :too_long, generate_message_options.merge(count: 5)] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :too_long, @person, generate_message_options.merge(count: 5)] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -234,8 +247,8 @@ class I18nValidationTest < ActiveModel::TestCase COMMON_CASES.each do |name, validation_options, generate_message_options| test "validates_length_of for :is on generated message #{name}" do person_class.validates_length_of :title, validation_options.merge(is: 5) - call = [:title, :wrong_length, generate_message_options.merge(count: 5)] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :wrong_length, @person, generate_message_options.merge(count: 5)] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -246,8 +259,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_format_of on generated message #{name}" do person_class.validates_format_of :title, validation_options.merge(with: /\A[1-9][0-9]*\z/) @person.title = "72x" - call = [:title, :invalid, generate_message_options.merge(value: "72x")] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :invalid, @person, generate_message_options.merge(value: "72x")] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -258,8 +271,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_inclusion_of on generated message #{name}" do person_class.validates_inclusion_of :title, validation_options.merge(in: %w(a b c)) @person.title = "z" - call = [:title, :inclusion, generate_message_options.merge(value: "z")] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :inclusion, @person, generate_message_options.merge(value: "z")] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -270,8 +283,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_inclusion_of using :within on generated message #{name}" do person_class.validates_inclusion_of :title, validation_options.merge(within: %w(a b c)) @person.title = "z" - call = [:title, :inclusion, generate_message_options.merge(value: "z")] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :inclusion, @person, generate_message_options.merge(value: "z")] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -282,8 +295,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_exclusion_of generated message #{name}" do person_class.validates_exclusion_of :title, validation_options.merge(in: %w(a b c)) @person.title = "a" - call = [:title, :exclusion, generate_message_options.merge(value: "a")] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :exclusion, @person, generate_message_options.merge(value: "a")] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -294,8 +307,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_exclusion_of using :within generated message #{name}" do person_class.validates_exclusion_of :title, validation_options.merge(within: %w(a b c)) @person.title = "a" - call = [:title, :exclusion, generate_message_options.merge(value: "a")] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :exclusion, @person, generate_message_options.merge(value: "a")] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -306,8 +319,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_numericality_of generated message #{name}" do person_class.validates_numericality_of :title, validation_options @person.title = "a" - call = [:title, :not_a_number, generate_message_options.merge(value: "a")] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :not_a_number, @person, generate_message_options.merge(value: "a")] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -318,8 +331,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_numericality_of for :only_integer on generated message #{name}" do person_class.validates_numericality_of :title, validation_options.merge(only_integer: true) @person.title = "0.0" - call = [:title, :not_an_integer, generate_message_options.merge(value: "0.0")] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :not_an_integer, @person, generate_message_options.merge(value: "0.0")] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -330,8 +343,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_numericality_of for :odd on generated message #{name}" do person_class.validates_numericality_of :title, validation_options.merge(only_integer: true, odd: true) @person.title = 0 - call = [:title, :odd, generate_message_options.merge(value: 0)] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :odd, @person, generate_message_options.merge(value: 0)] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end @@ -342,8 +355,8 @@ class I18nValidationTest < ActiveModel::TestCase test "validates_numericality_of for :less_than on generated message #{name}" do person_class.validates_numericality_of :title, validation_options.merge(only_integer: true, less_than: 0) @person.title = 1 - call = [:title, :less_than, generate_message_options.merge(value: 1, count: 0)] - assert_called_with(@person.errors, :generate_message, call) do + call = [:title, :less_than, @person, generate_message_options.merge(value: 1, count: 0)] + assert_called_with(ActiveModel::Error, :generate_message, call) do @person.valid? @person.errors.messages end |