aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/test
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel/test')
-rw-r--r--activemodel/test/cases/attribute_methods_test.rb1
-rw-r--r--activemodel/test/cases/attributes_test.rb14
-rw-r--r--activemodel/test/cases/error_test.rb200
-rw-r--r--activemodel/test/cases/errors_test.rb371
-rw-r--r--activemodel/test/cases/nested_error_test.rb54
-rw-r--r--activemodel/test/cases/railtie_test.rb6
-rw-r--r--activemodel/test/cases/type/date_time_test.rb1
-rw-r--r--activemodel/test/cases/validations/acceptance_validation_test.rb1
-rw-r--r--activemodel/test/cases/validations/i18n_validation_test.rb118
-rw-r--r--activemodel/test/cases/validations/numericality_validation_test.rb1
-rw-r--r--activemodel/test/cases/validations/validations_context_test.rb4
-rw-r--r--activemodel/test/cases/validations/with_validation_test.rb8
-rw-r--r--activemodel/test/cases/validations_test.rb14
-rw-r--r--activemodel/test/models/person_with_validator.rb2
-rw-r--r--activemodel/test/models/reply.rb10
-rw-r--r--activemodel/test/validators/email_validator.rb5
16 files changed, 696 insertions, 114 deletions
diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb
index 4e228032c3..e3b3b15f25 100644
--- a/activemodel/test/cases/attribute_methods_test.rb
+++ b/activemodel/test/cases/attribute_methods_test.rb
@@ -40,7 +40,6 @@ private
end
protected
-
def protected_method
"O_o O_o"
end
diff --git a/activemodel/test/cases/attributes_test.rb b/activemodel/test/cases/attributes_test.rb
index 5483fb101d..af0ddcb92f 100644
--- a/activemodel/test/cases/attributes_test.rb
+++ b/activemodel/test/cases/attributes_test.rb
@@ -67,6 +67,20 @@ module ActiveModel
assert_equal expected_attributes, data.attributes
end
+ test "reading attribute names" do
+ names = [
+ "integer_field",
+ "string_field",
+ "decimal_field",
+ "string_with_default",
+ "date_field",
+ "boolean_field"
+ ]
+
+ assert_equal names, ModelForAttributesTest.attribute_names
+ assert_equal names, ModelForAttributesTest.new.attribute_names
+ end
+
test "nonexistent attribute" do
assert_raise ActiveModel::UnknownAttributeError do
ModelForAttributesTest.new(nonexistent: "nonexistent")
diff --git a/activemodel/test/cases/error_test.rb b/activemodel/test/cases/error_test.rb
new file mode 100644
index 0000000000..d74321fee5
--- /dev/null
+++ b/activemodel/test/cases/error_test.rb
@@ -0,0 +1,200 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "active_model/error"
+
+class ErrorTest < ActiveModel::TestCase
+ class Person
+ extend ActiveModel::Naming
+ def initialize
+ @errors = ActiveModel::Errors.new(self)
+ end
+
+ attr_accessor :name, :age
+ attr_reader :errors
+
+ def read_attribute_for_validation(attr)
+ send(attr)
+ end
+
+ def self.human_attribute_name(attr, options = {})
+ attr
+ end
+
+ def self.lookup_ancestors
+ [self]
+ end
+ end
+
+ def test_initialize
+ base = Person.new
+ error = ActiveModel::Error.new(base, :name, :too_long, foo: :bar)
+ assert_equal base, error.base
+ assert_equal :name, error.attribute
+ assert_equal :too_long, error.type
+ assert_equal({ foo: :bar }, error.options)
+ end
+
+ test "initialize without type" do
+ error = ActiveModel::Error.new(Person.new, :name)
+ assert_equal :invalid, error.type
+ assert_equal({}, error.options)
+ end
+
+ test "initialize without type but with options" do
+ options = { message: "bar" }
+ error = ActiveModel::Error.new(Person.new, :name, options)
+ assert_equal(options, error.options)
+ end
+
+ # match?
+
+ test "match? handles mixed condition" do
+ subject = ActiveModel::Error.new(Person.new, :mineral, :not_enough, count: 2)
+ assert_not subject.match?(:mineral, :too_coarse)
+ assert subject.match?(:mineral, :not_enough)
+ assert subject.match?(:mineral, :not_enough, count: 2)
+ assert_not subject.match?(:mineral, :not_enough, count: 1)
+ end
+
+ test "match? handles attribute match" do
+ subject = ActiveModel::Error.new(Person.new, :mineral, :not_enough, count: 2)
+ assert_not subject.match?(:foo)
+ assert subject.match?(:mineral)
+ end
+
+ test "match? handles error type match" do
+ subject = ActiveModel::Error.new(Person.new, :mineral, :not_enough, count: 2)
+ assert_not subject.match?(:mineral, :too_coarse)
+ assert subject.match?(:mineral, :not_enough)
+ end
+
+ test "match? handles extra options match" do
+ subject = ActiveModel::Error.new(Person.new, :mineral, :not_enough, count: 2)
+ assert_not subject.match?(:mineral, :not_enough, count: 1)
+ assert subject.match?(:mineral, :not_enough, count: 2)
+ end
+
+ # message
+
+ test "message with type as a symbol" do
+ error = ActiveModel::Error.new(Person.new, :name, :blank)
+ assert_equal "can't be blank", error.message
+ end
+
+ test "message with custom interpolation" do
+ subject = ActiveModel::Error.new(Person.new, :name, :inclusion, message: "custom message %{value}", value: "name")
+ assert_equal "custom message name", subject.message
+ end
+
+ test "message returns plural interpolation" do
+ subject = ActiveModel::Error.new(Person.new, :name, :too_long, count: 10)
+ assert_equal "is too long (maximum is 10 characters)", subject.message
+ end
+
+ test "message returns singular interpolation" do
+ subject = ActiveModel::Error.new(Person.new, :name, :too_long, count: 1)
+ assert_equal "is too long (maximum is 1 character)", subject.message
+ end
+
+ test "message returns count interpolation" do
+ subject = ActiveModel::Error.new(Person.new, :name, :too_long, message: "custom message %{count}", count: 10)
+ assert_equal "custom message 10", subject.message
+ end
+
+ test "message handles lambda in messages and option values, and i18n interpolation" do
+ subject = ActiveModel::Error.new(Person.new, :name, :invalid,
+ foo: "foo",
+ bar: "bar",
+ baz: Proc.new { "baz" },
+ message: Proc.new { |model, options|
+ "%{attribute} %{foo} #{options[:bar]} %{baz}"
+ }
+ )
+ assert_equal "name foo bar baz", subject.message
+ end
+
+ test "generate_message works without i18n_scope" do
+ person = Person.new
+ error = ActiveModel::Error.new(person, :name, :blank)
+ assert_not_respond_to Person, :i18n_scope
+ assert_nothing_raised {
+ error.message
+ }
+ end
+
+ test "message with type as custom message" do
+ error = ActiveModel::Error.new(Person.new, :name, message: "cannot be blank")
+ assert_equal "cannot be blank", error.message
+ end
+
+ test "message with options[:message] as custom message" do
+ error = ActiveModel::Error.new(Person.new, :name, :blank, message: "cannot be blank")
+ assert_equal "cannot be blank", error.message
+ end
+
+ test "message renders lazily using current locale" do
+ error = nil
+
+ I18n.backend.store_translations(:pl, errors: { messages: { invalid: "jest nieprawidłowe" } })
+
+ I18n.with_locale(:en) { error = ActiveModel::Error.new(Person.new, :name, :invalid) }
+ I18n.with_locale(:pl) {
+ assert_equal "jest nieprawidłowe", error.message
+ }
+ end
+
+ test "message uses current locale" do
+ I18n.backend.store_translations(:en, errors: { messages: { inadequate: "Inadequate %{attribute} found!" } })
+ error = ActiveModel::Error.new(Person.new, :name, :inadequate)
+ assert_equal "Inadequate name found!", error.message
+ end
+
+ # full_message
+
+ test "full_message returns the given message when attribute is :base" do
+ error = ActiveModel::Error.new(Person.new, :base, message: "press the button")
+ assert_equal "press the button", error.full_message
+ end
+
+ test "full_message returns the given message with the attribute name included" do
+ error = ActiveModel::Error.new(Person.new, :name, :blank)
+ assert_equal "name can't be blank", error.full_message
+ end
+
+ test "full_message uses default format" do
+ error = ActiveModel::Error.new(Person.new, :name, message: "can't be blank")
+
+ # Use a locale without errors.format
+ I18n.with_locale(:unknown) {
+ assert_equal "name can't be blank", error.full_message
+ }
+ end
+
+ test "equality by base attribute, type and options" do
+ person = Person.new
+
+ e1 = ActiveModel::Error.new(person, :name, foo: :bar)
+ e2 = ActiveModel::Error.new(person, :name, foo: :bar)
+ e2.instance_variable_set(:@_humanized_attribute, "Name")
+
+ assert_equal(e1, e2)
+ end
+
+ test "inequality" do
+ person = Person.new
+ error = ActiveModel::Error.new(person, :name, foo: :bar)
+
+ assert error != ActiveModel::Error.new(person, :name, foo: :baz)
+ assert error != ActiveModel::Error.new(person, :name)
+ assert error != ActiveModel::Error.new(person, :title, foo: :bar)
+ assert error != ActiveModel::Error.new(Person.new, :name, foo: :bar)
+ end
+
+ test "comparing against different class would not raise error" do
+ person = Person.new
+ error = ActiveModel::Error.new(person, :name, foo: :bar)
+
+ assert error != person
+ end
+end
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index 947f9bf99b..a6cd1da717 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -10,7 +10,7 @@ class ErrorsTest < ActiveModel::TestCase
@errors = ActiveModel::Errors.new(self)
end
- attr_accessor :name, :age
+ attr_accessor :name, :age, :gender, :city
attr_reader :errors
def validate!
@@ -31,48 +31,66 @@ class ErrorsTest < ActiveModel::TestCase
end
def test_delete
- errors = ActiveModel::Errors.new(self)
- errors[:foo] << "omg"
- errors.delete("foo")
- assert_empty errors[:foo]
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name, :blank)
+ errors.delete("name")
+ assert_empty errors[:name]
end
def test_include?
- errors = ActiveModel::Errors.new(self)
- errors[:foo] << "omg"
+ errors = ActiveModel::Errors.new(Person.new)
+ assert_deprecated { errors[:foo] << "omg" }
assert_includes errors, :foo, "errors should include :foo"
assert_includes errors, "foo", "errors should include 'foo' as :foo"
end
+ def test_each_when_arity_is_negative
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name, :blank)
+ errors.add(:gender, :blank)
+
+ assert_equal([:name, :gender], errors.map(&:attribute))
+ end
+
+ def test_any?
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name)
+ assert_not_deprecated {
+ assert errors.any?, "any? should return true"
+ }
+ assert_not_deprecated {
+ assert errors.any? { |_| true }, "any? should return true"
+ }
+ end
+
def test_dup
- errors = ActiveModel::Errors.new(self)
- errors[:foo] << "bar"
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name)
errors_dup = errors.dup
- errors_dup[:bar] << "omg"
- assert_not_same errors_dup.messages, errors.messages
+ assert_not_same errors_dup.errors, errors.errors
end
def test_has_key?
- errors = ActiveModel::Errors.new(self)
- errors[:foo] << "omg"
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:foo, "omg")
assert_equal true, errors.has_key?(:foo), "errors should have key :foo"
assert_equal true, errors.has_key?("foo"), "errors should have key 'foo' as :foo"
end
def test_has_no_key
- errors = ActiveModel::Errors.new(self)
+ errors = ActiveModel::Errors.new(Person.new)
assert_equal false, errors.has_key?(:name), "errors should not have key :name"
end
def test_key?
- errors = ActiveModel::Errors.new(self)
- errors[:foo] << "omg"
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:foo, "omg")
assert_equal true, errors.key?(:foo), "errors should have key :foo"
assert_equal true, errors.key?("foo"), "errors should have key 'foo' as :foo"
end
def test_no_key
- errors = ActiveModel::Errors.new(self)
+ errors = ActiveModel::Errors.new(Person.new)
assert_equal false, errors.key?(:name), "errors should not have key :name"
end
@@ -86,42 +104,58 @@ class ErrorsTest < ActiveModel::TestCase
end
test "error access is indifferent" do
- errors = ActiveModel::Errors.new(self)
- errors[:foo] << "omg"
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name, "omg")
- assert_equal ["omg"], errors["foo"]
+ assert_equal ["omg"], errors["name"]
end
test "values returns an array of messages" do
+ errors = ActiveModel::Errors.new(Person.new)
+ assert_deprecated { errors.messages[:foo] = "omg" }
+ assert_deprecated { errors.messages[:baz] = "zomg" }
+
+ assert_deprecated do
+ assert_equal ["omg", "zomg"], errors.values
+ end
+ end
+
+ test "[]= overrides values" do
errors = ActiveModel::Errors.new(self)
- errors.messages[:foo] = "omg"
- errors.messages[:baz] = "zomg"
+ assert_deprecated { errors.messages[:foo] = "omg" }
+ assert_deprecated { errors.messages[:foo] = "zomg" }
- assert_equal ["omg", "zomg"], errors.values
+ assert_equal ["zomg"], errors[:foo]
end
test "values returns an empty array after try to get a message only" do
- errors = ActiveModel::Errors.new(self)
+ errors = ActiveModel::Errors.new(Person.new)
errors.messages[:foo]
errors.messages[:baz]
- assert_equal [], errors.values
+ assert_deprecated do
+ assert_equal [], errors.values
+ end
end
test "keys returns the error keys" do
- errors = ActiveModel::Errors.new(self)
- errors.messages[:foo] << "omg"
- errors.messages[:baz] << "zomg"
+ errors = ActiveModel::Errors.new(Person.new)
+ assert_deprecated { errors.messages[:foo] << "omg" }
+ assert_deprecated { errors.messages[:baz] << "zomg" }
- assert_equal [:foo, :baz], errors.keys
+ assert_deprecated do
+ assert_equal [:foo, :baz], errors.keys
+ end
end
test "keys returns an empty array after try to get a message only" do
- errors = ActiveModel::Errors.new(self)
+ errors = ActiveModel::Errors.new(Person.new)
errors.messages[:foo]
errors.messages[:baz]
- assert_equal [], errors.keys
+ assert_deprecated do
+ assert_equal [], errors.keys
+ end
end
test "detecting whether there are errors with empty?, blank?, include?" do
@@ -146,32 +180,130 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal ["cannot be nil"], person.errors[:name]
end
- test "add an error message on a specific attribute" do
+ test "add an error message on a specific attribute (deprecated)" do
person = Person.new
person.errors.add(:name, "cannot be blank")
assert_equal ["cannot be blank"], person.errors[:name]
end
- test "add an error message on a specific attribute with a defined type" do
+ test "add an error message on a specific attribute with a defined type (deprecated)" do
person = Person.new
person.errors.add(:name, :blank, message: "cannot be blank")
assert_equal ["cannot be blank"], person.errors[:name]
end
- test "add an error with a symbol" do
+ test "add an error with a symbol (deprecated)" do
person = Person.new
person.errors.add(:name, :blank)
message = person.errors.generate_message(:name, :blank)
assert_equal [message], person.errors[:name]
end
- test "add an error with a proc" do
+ test "add an error with a proc (deprecated)" do
person = Person.new
message = Proc.new { "cannot be blank" }
person.errors.add(:name, message)
assert_equal ["cannot be blank"], person.errors[:name]
end
+ test "add creates an error object and returns it" do
+ person = Person.new
+ error = person.errors.add(:name, :blank)
+
+ assert_equal :name, error.attribute
+ assert_equal :blank, error.type
+ assert_equal error, person.errors.objects.first
+ end
+
+ test "add, with type as symbol" do
+ person = Person.new
+ person.errors.add(:name, :blank)
+
+ assert_equal :blank, person.errors.objects.first.type
+ assert_equal ["can't be blank"], person.errors[:name]
+ end
+
+ test "add, with type as String" do
+ msg = "custom msg"
+
+ person = Person.new
+ person.errors.add(:name, msg)
+
+ assert_equal [msg], person.errors[:name]
+ end
+
+ test "add, with type as nil" do
+ person = Person.new
+ person.errors.add(:name)
+
+ assert_equal :invalid, person.errors.objects.first.type
+ assert_equal ["is invalid"], person.errors[:name]
+ end
+
+ test "add, with type as Proc, which evaluates to String" do
+ msg = "custom msg"
+ type = Proc.new { msg }
+
+ person = Person.new
+ person.errors.add(:name, type)
+
+ assert_equal [msg], person.errors[:name]
+ end
+
+ test "add, type being Proc, which evaluates to Symbol" do
+ type = Proc.new { :blank }
+
+ person = Person.new
+ person.errors.add(:name, type)
+
+ assert_equal :blank, person.errors.objects.first.type
+ assert_equal ["can't be blank"], person.errors[:name]
+ end
+
+ test "initialize options[:message] as Proc, which evaluates to String" do
+ msg = "custom msg"
+ type = Proc.new { msg }
+
+ person = Person.new
+ person.errors.add(:name, :blank, message: type)
+
+ assert_equal :blank, person.errors.objects.first.type
+ assert_equal [msg], person.errors[:name]
+ end
+
+ test "add, with options[:message] as Proc, which evaluates to String, where type is nil" do
+ msg = "custom msg"
+ type = Proc.new { msg }
+
+ person = Person.new
+ person.errors.add(:name, message: type)
+
+ assert_equal :invalid, person.errors.objects.first.type
+ 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")
@@ -342,6 +474,17 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal ["name cannot be blank", "name cannot be nil"], person.errors.to_a
end
+ test "to_h is deprecated" do
+ person = Person.new
+ person.errors.add(:name, "cannot be blank")
+ person.errors.add(:name, "too long")
+
+ expected_deprecation = "ActiveModel::Errors#to_h is deprecated"
+ assert_deprecated(expected_deprecation) do
+ assert_equal({ name: "too long" }, person.errors.to_h)
+ end
+ end
+
test "to_hash returns the error messages hash" do
person = Person.new
person.errors.add(:name, "cannot be blank")
@@ -358,6 +501,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")
@@ -437,6 +601,32 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal({ name: [{ error: :invalid }] }, person.errors.details)
end
+ test "details retains original type as error" do
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name, "cannot be nil")
+ errors.add("foo", "bar")
+ errors.add(:baz, nil)
+ errors.add(:age, :invalid, count: 3, message: "%{count} is too low")
+
+ assert_equal(
+ {
+ name: [{ error: "cannot be nil" }],
+ foo: [{ error: "bar" }],
+ baz: [{ error: nil }],
+ age: [{ error: :invalid, count: 3 }]
+ },
+ errors.details
+ )
+ end
+
+ test "group_by_attribute" do
+ person = Person.new
+ error = person.errors.add(:name, :invalid, message: "is bad")
+ hash = person.errors.group_by_attribute
+
+ assert_equal({ name: [error] }, hash)
+ end
+
test "dup duplicates details" do
errors = ActiveModel::Errors.new(Person.new)
errors.add(:name, :invalid)
@@ -445,11 +635,17 @@ 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)
errors.delete(:name)
- assert_empty errors.details[:name]
+ assert_not errors.added?(:name)
end
test "delete returns the deleted messages" do
@@ -467,7 +663,7 @@ class ErrorsTest < ActiveModel::TestCase
assert_empty person.errors.details
end
- test "copy errors" do
+ test "copy errors (deprecated)" do
errors = ActiveModel::Errors.new(Person.new)
errors.add(:name, :invalid)
person = Person.new
@@ -477,7 +673,25 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal [:name], person.errors.details.keys
end
- test "merge errors" do
+ test "details returns empty array when accessed with non-existent attribute" do
+ errors = ActiveModel::Errors.new(Person.new)
+
+ assert_equal [], errors.details[:foo]
+ end
+
+ test "copy errors" do
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name, :invalid)
+ person = Person.new
+ person.errors.copy!(errors)
+
+ assert person.errors.added?(:name, :invalid)
+ person.errors.each do |error|
+ assert_same person, error.base
+ end
+ end
+
+ test "merge errors (deprecated)" do
errors = ActiveModel::Errors.new(Person.new)
errors.add(:name, :invalid)
@@ -489,6 +703,18 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal({ name: [{ error: :blank }, { error: :invalid }] }, person.errors.details)
end
+ test "merge errors" do
+ errors = ActiveModel::Errors.new(Person.new)
+ errors.add(:name, :invalid)
+
+ person = Person.new
+ person.errors.add(:name, :blank)
+ person.errors.merge!(errors)
+
+ assert(person.errors.added?(:name, :invalid))
+ assert(person.errors.added?(:name, :blank))
+ end
+
test "slice! removes all errors except the given keys" do
person = Person.new
person.errors.add(:name, "cannot be nil")
@@ -496,9 +722,9 @@ class ErrorsTest < ActiveModel::TestCase
person.errors.add(:gender, "cannot be nil")
person.errors.add(:city, "cannot be nil")
- person.errors.slice!(:age, "gender")
+ assert_deprecated { person.errors.slice!(:age, "gender") }
- assert_equal [:age, :gender], person.errors.keys
+ assert_equal [:age, :gender], assert_deprecated { person.errors.keys }
end
test "slice! returns the deleted errors" do
@@ -508,7 +734,7 @@ class ErrorsTest < ActiveModel::TestCase
person.errors.add(:gender, "cannot be nil")
person.errors.add(:city, "cannot be nil")
- removed_errors = person.errors.slice!(:age, "gender")
+ removed_errors = assert_deprecated { person.errors.slice!(:age, "gender") }
assert_equal({ name: ["cannot be nil"], city: ["cannot be nil"] }, removed_errors)
end
@@ -518,10 +744,23 @@ class ErrorsTest < ActiveModel::TestCase
errors.add(:name, :invalid)
serialized = Marshal.load(Marshal.dump(errors))
+ assert_equal Person, serialized.instance_variable_get(:@base).class
assert_equal errors.messages, serialized.messages
assert_equal errors.details, serialized.details
end
+ test "errors are compatible with marshal dumped from Rails 5.x" do
+ # Derived from
+ # errors = ActiveModel::Errors.new(Person.new)
+ # errors.add(:name, :invalid)
+ dump = "\x04\bU:\x18ActiveModel::Errors[\bo:\x17ErrorsTest::Person\x06:\f@errorsU;\x00[\b@\a{\x00{\x00{\x06:\tname[\x06I\"\x0Fis invalid\x06:\x06ET{\x06;\b[\x06{\x06:\nerror:\finvalid"
+ serialized = Marshal.load(dump)
+
+ assert_equal Person, serialized.instance_variable_get(:@base).class
+ assert_equal({ name: ["is invalid"] }, serialized.messages)
+ assert_equal({ name: [{ error: :invalid }] }, serialized.details)
+ end
+
test "errors are backward compatible with the Rails 4.2 format" do
yaml = <<~CODE
--- !ruby/object:ActiveModel::Errors
@@ -541,4 +780,54 @@ class ErrorsTest < ActiveModel::TestCase
assert_equal({}, errors.messages)
assert_equal({}, errors.details)
end
+
+ test "errors are compatible with YAML dumped from Rails 5.x" do
+ yaml = <<~CODE
+ --- !ruby/object:ActiveModel::Errors
+ base: &1 !ruby/object:ErrorsTest::Person
+ errors: !ruby/object:ActiveModel::Errors
+ base: *1
+ messages: {}
+ details: {}
+ messages:
+ :name:
+ - is invalid
+ details:
+ :name:
+ - :error: :invalid
+ CODE
+
+ errors = YAML.load(yaml)
+ assert_equal({ name: ["is invalid"] }, errors.messages)
+ assert_equal({ name: [{ error: :invalid }] }, errors.details)
+
+ errors.clear
+ assert_equal({}, errors.messages)
+ assert_equal({}, errors.details)
+ end
+
+ test "errors are compatible with YAML dumped from Rails 6.x" do
+ yaml = <<~CODE
+ --- !ruby/object:ActiveModel::Errors
+ base: &1 !ruby/object:ErrorsTest::Person
+ errors: !ruby/object:ActiveModel::Errors
+ base: *1
+ errors: []
+ errors:
+ - !ruby/object:ActiveModel::Error
+ base: *1
+ attribute: :name
+ type: :invalid
+ raw_type: :invalid
+ options: {}
+ CODE
+
+ errors = YAML.load(yaml)
+ assert_equal({ name: ["is invalid"] }, errors.messages)
+ assert_equal({ name: [{ error: :invalid }] }, errors.details)
+
+ errors.clear
+ assert_equal({}, errors.messages)
+ assert_equal({}, errors.details)
+ end
end
diff --git a/activemodel/test/cases/nested_error_test.rb b/activemodel/test/cases/nested_error_test.rb
new file mode 100644
index 0000000000..6c2458ba83
--- /dev/null
+++ b/activemodel/test/cases/nested_error_test.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "active_model/nested_error"
+require "models/topic"
+require "models/reply"
+
+class NestedErrorTest < ActiveModel::TestCase
+ def test_initialize
+ topic = Topic.new
+ inner_error = ActiveModel::Error.new(topic, :title, :not_enough, count: 2)
+ reply = Reply.new
+ error = ActiveModel::NestedError.new(reply, inner_error)
+
+ assert_equal reply, error.base
+ assert_equal inner_error.attribute, error.attribute
+ assert_equal inner_error.type, error.type
+ assert_equal(inner_error.options, error.options)
+ end
+
+ test "initialize with overriding attribute and type" do
+ topic = Topic.new
+ inner_error = ActiveModel::Error.new(topic, :title, :not_enough, count: 2)
+ reply = Reply.new
+ error = ActiveModel::NestedError.new(reply, inner_error, attribute: :parent, type: :foo)
+
+ assert_equal reply, error.base
+ assert_equal :parent, error.attribute
+ assert_equal :foo, error.type
+ assert_equal(inner_error.options, error.options)
+ end
+
+ def test_message
+ topic = Topic.new(author_name: "Bruce")
+ inner_error = ActiveModel::Error.new(topic, :title, :not_enough, message: Proc.new { |model, options|
+ "not good enough for #{model.author_name}"
+ })
+ reply = Reply.new(author_name: "Mark")
+ error = ActiveModel::NestedError.new(reply, inner_error)
+
+ assert_equal "not good enough for Bruce", error.message
+ end
+
+ def test_full_message
+ topic = Topic.new(author_name: "Bruce")
+ inner_error = ActiveModel::Error.new(topic, :title, :not_enough, message: Proc.new { |model, options|
+ "not good enough for #{model.author_name}"
+ })
+ reply = Reply.new(author_name: "Mark")
+ error = ActiveModel::NestedError.new(reply, inner_error)
+
+ assert_equal "Title not good enough for Bruce", error.full_message
+ end
+end
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/type/date_time_test.rb b/activemodel/test/cases/type/date_time_test.rb
index 74b47d1b4d..4a63eee0cf 100644
--- a/activemodel/test/cases/type/date_time_test.rb
+++ b/activemodel/test/cases/type/date_time_test.rb
@@ -37,7 +37,6 @@ module ActiveModel
end
private
-
def with_timezone_config(default:)
old_zone_default = ::Time.zone_default
::Time.zone_default = ::Time.find_zone(default)
diff --git a/activemodel/test/cases/validations/acceptance_validation_test.rb b/activemodel/test/cases/validations/acceptance_validation_test.rb
index 72baf6e7a7..6bd3d292f8 100644
--- a/activemodel/test/cases/validations/acceptance_validation_test.rb
+++ b/activemodel/test/cases/validations/acceptance_validation_test.rb
@@ -92,7 +92,6 @@ class AcceptanceValidationTest < ActiveModel::TestCase
end
private
-
# Acceptance validator includes anonymous module into class, which cannot
# be cleared, so to avoid multiple inclusions we use a named subclass which
# we can remove in teardown.
diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb
index 35bb918f26..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" } }
@@ -169,8 +182,8 @@ class I18nValidationTest < ActiveModel::TestCase
# [ case, validation_options, generate_message_options]
[ "given no options", {}, {}],
[ "given custom message", { message: "custom" }, { message: "custom" }],
- [ "given if condition", { if: lambda { true } }, {}],
- [ "given unless condition", { unless: lambda { false } }, {}],
+ [ "given if condition", { if: lambda { true } }, {}],
+ [ "given unless condition", { unless: lambda { false } }, {}],
[ "given option that is not reserved", { format: "jpg" }, { format: "jpg" }]
]
@@ -178,9 +191,10 @@ 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
end
end
@@ -188,9 +202,10 @@ 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
end
end
@@ -198,9 +213,10 @@ 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
end
end
@@ -208,9 +224,10 @@ 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
end
end
@@ -219,9 +236,10 @@ 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
end
end
@@ -229,9 +247,10 @@ 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
end
end
@@ -240,9 +259,10 @@ 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
end
end
@@ -251,9 +271,10 @@ 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
end
end
@@ -262,9 +283,10 @@ 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
end
end
@@ -273,9 +295,10 @@ 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
end
end
@@ -284,9 +307,10 @@ 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
end
end
@@ -295,9 +319,10 @@ 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
end
end
@@ -306,9 +331,10 @@ 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
end
end
@@ -317,9 +343,10 @@ 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
end
end
@@ -328,9 +355,10 @@ 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
end
end
diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb
index 16c44762cb..191af033df 100644
--- a/activemodel/test/cases/validations/numericality_validation_test.rb
+++ b/activemodel/test/cases/validations/numericality_validation_test.rb
@@ -310,7 +310,6 @@ class NumericalityValidationTest < ActiveModel::TestCase
end
private
-
def invalid!(values, error = nil)
with_each_topic_approved_value(values) do |topic, value|
assert topic.invalid?, "#{value.inspect} not rejected as a number"
diff --git a/activemodel/test/cases/validations/validations_context_test.rb b/activemodel/test/cases/validations/validations_context_test.rb
index 024eb1882f..3d2dea9828 100644
--- a/activemodel/test/cases/validations/validations_context_test.rb
+++ b/activemodel/test/cases/validations/validations_context_test.rb
@@ -14,13 +14,13 @@ class ValidationsContextTest < ActiveModel::TestCase
class ValidatorThatAddsErrors < ActiveModel::Validator
def validate(record)
- record.errors[:base] << ERROR_MESSAGE
+ record.errors.add(:base, ERROR_MESSAGE)
end
end
class AnotherValidatorThatAddsErrors < ActiveModel::Validator
def validate(record)
- record.errors[:base] << ANOTHER_ERROR_MESSAGE
+ record.errors.add(:base, ANOTHER_ERROR_MESSAGE)
end
end
diff --git a/activemodel/test/cases/validations/with_validation_test.rb b/activemodel/test/cases/validations/with_validation_test.rb
index 8239792c79..e6ae6603f2 100644
--- a/activemodel/test/cases/validations/with_validation_test.rb
+++ b/activemodel/test/cases/validations/with_validation_test.rb
@@ -14,13 +14,13 @@ class ValidatesWithTest < ActiveModel::TestCase
class ValidatorThatAddsErrors < ActiveModel::Validator
def validate(record)
- record.errors[:base] << ERROR_MESSAGE
+ record.errors.add(:base, message: ERROR_MESSAGE)
end
end
class OtherValidatorThatAddsErrors < ActiveModel::Validator
def validate(record)
- record.errors[:base] << OTHER_ERROR_MESSAGE
+ record.errors.add(:base, message: OTHER_ERROR_MESSAGE)
end
end
@@ -32,14 +32,14 @@ class ValidatesWithTest < ActiveModel::TestCase
class ValidatorThatValidatesOptions < ActiveModel::Validator
def validate(record)
if options[:field] == :first_name
- record.errors[:base] << ERROR_MESSAGE
+ record.errors.add(:base, message: ERROR_MESSAGE)
end
end
end
class ValidatorPerEachAttribute < ActiveModel::EachValidator
def validate_each(record, attribute, value)
- record.errors[attribute] << "Value is #{value}"
+ record.errors.add(attribute, message: "Value is #{value}")
end
end
diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb
index 7776233db5..0b9e1b7005 100644
--- a/activemodel/test/cases/validations_test.rb
+++ b/activemodel/test/cases/validations_test.rb
@@ -53,7 +53,7 @@ class ValidationsTest < ActiveModel::TestCase
r = Reply.new
r.valid?
- errors = r.errors.collect { |attr, messages| [attr.to_s, messages] }
+ errors = assert_deprecated { r.errors.collect { |attr, messages| [attr.to_s, messages] } }
assert_includes errors, ["title", "is Empty"]
assert_includes errors, ["content", "is Empty"]
@@ -74,7 +74,7 @@ class ValidationsTest < ActiveModel::TestCase
def test_errors_on_nested_attributes_expands_name
t = Topic.new
- t.errors["replies.name"] << "can't be blank"
+ assert_deprecated { t.errors["replies.name"] << "can't be blank" }
assert_equal ["Replies name can't be blank"], t.errors.full_messages
end
@@ -216,7 +216,7 @@ class ValidationsTest < ActiveModel::TestCase
t = Topic.new
assert_predicate t, :invalid?
- xml = t.errors.to_xml
+ xml = assert_deprecated { t.errors.to_xml }
assert_match %r{<errors>}, xml
assert_match %r{<error>Title can't be blank</error>}, xml
assert_match %r{<error>Content can't be blank</error>}, xml
@@ -241,14 +241,14 @@ class ValidationsTest < ActiveModel::TestCase
t = Topic.new title: ""
assert_predicate t, :invalid?
- assert_equal :title, key = t.errors.keys[0]
+ assert_equal :title, key = assert_deprecated { t.errors.keys[0] }
assert_equal "can't be blank", t.errors[key][0]
assert_equal "is too short (minimum is 2 characters)", t.errors[key][1]
- assert_equal :author_name, key = t.errors.keys[1]
+ assert_equal :author_name, key = assert_deprecated { t.errors.keys[1] }
assert_equal "can't be blank", t.errors[key][0]
- assert_equal :author_email_address, key = t.errors.keys[2]
+ assert_equal :author_email_address, key = assert_deprecated { t.errors.keys[2] }
assert_equal "will never be valid", t.errors[key][0]
- assert_equal :content, key = t.errors.keys[3]
+ assert_equal :content, key = assert_deprecated { t.errors.keys[3] }
assert_equal "is too short (minimum is 2 characters)", t.errors[key][0]
end
diff --git a/activemodel/test/models/person_with_validator.rb b/activemodel/test/models/person_with_validator.rb
index 44e78cbc29..fbb28d2a0f 100644
--- a/activemodel/test/models/person_with_validator.rb
+++ b/activemodel/test/models/person_with_validator.rb
@@ -5,7 +5,7 @@ class PersonWithValidator
class PresenceValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
- record.errors[attribute] << "Local validator#{options[:custom]}" if value.blank?
+ record.errors.add(attribute, message: "Local validator#{options[:custom]}") if value.blank?
end
end
diff --git a/activemodel/test/models/reply.rb b/activemodel/test/models/reply.rb
index 6bb18f95fe..f340b6fb14 100644
--- a/activemodel/test/models/reply.rb
+++ b/activemodel/test/models/reply.rb
@@ -11,24 +11,24 @@ class Reply < Topic
validate :check_wrong_update, on: :update
def check_empty_title
- errors[:title] << "is Empty" unless title && title.size > 0
+ errors.add(:title, "is Empty") unless title && title.size > 0
end
def errors_on_empty_content
- errors[:content] << "is Empty" unless content && content.size > 0
+ errors.add(:content, "is Empty") unless content && content.size > 0
end
def check_content_mismatch
if title && content && content == "Mismatch"
- errors[:title] << "is Content Mismatch"
+ errors.add(:title, "is Content Mismatch")
end
end
def title_is_wrong_create
- errors[:title] << "is Wrong Create" if title && title == "Wrong Create"
+ errors.add(:title, "is Wrong Create") if title && title == "Wrong Create"
end
def check_wrong_update
- errors[:title] << "is Wrong Update" if title && title == "Wrong Update"
+ errors.add(:title, "is Wrong Update") if title && title == "Wrong Update"
end
end
diff --git a/activemodel/test/validators/email_validator.rb b/activemodel/test/validators/email_validator.rb
index 0c634d8659..774a10b2ba 100644
--- a/activemodel/test/validators/email_validator.rb
+++ b/activemodel/test/validators/email_validator.rb
@@ -2,7 +2,8 @@
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
- record.errors[attribute] << (options[:message] || "is not an email") unless
- /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i.match?(value)
+ unless /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i.match?(value)
+ record.errors.add(attribute, message: options[:message] || "is not an email")
+ end
end
end