Add `ActiveModel::Errors#of_kind?`

Related to https://github.com/rails/rails/pull/34817#issuecomment-451508668
This commit is contained in:
bogdanvlviv 2019-01-04 20:35:17 +02:00
parent de50002723
commit d5c26c43c0
No known key found for this signature in database
GPG Key ID: E4ACD76A6DB6DFDD
3 changed files with 112 additions and 9 deletions

View File

@ -1,3 +1,7 @@
* Add `ActiveModel::Errors#of_kind?`.
*bogdanvlviv*, *Rafael Mendonça França*
* Fix numericality equality validation of `BigDecimal` and `Float`
by casting to `BigDecimal` on both ends of the validation.

View File

@ -328,15 +328,15 @@ module ActiveModel
# person.errors.added? :name, :blank # => true
# person.errors.added? :name, "can't be blank" # => true
#
# If the error message requires an option, then it returns +true+ with
# the correct option, or +false+ with an incorrect or missing option.
# If the error message requires options, then it returns +true+ with
# the correct options, or +false+ with incorrect or missing options.
#
# person.errors.add :name, :too_long, { count: 25 }
# person.errors.added? :name, :too_long, count: 25 # => true
# person.errors.added? :name, "is too long (maximum is 25 characters)" # => true
# person.errors.added? :name, :too_long, count: 24 # => false
# person.errors.added? :name, :too_long # => false
# person.errors.added? :name, "is too long" # => false
# person.errors.add :name, :too_long, { count: 25 }
# person.errors.added? :name, :too_long, count: 25 # => true
# person.errors.added? :name, "is too long (maximum is 25 characters)" # => true
# person.errors.added? :name, :too_long, count: 24 # => false
# person.errors.added? :name, :too_long # => false
# person.errors.added? :name, "is too long" # => false
def added?(attribute, message = :invalid, options = {})
message = message.call if message.respond_to?(:call)
@ -347,6 +347,27 @@ module ActiveModel
end
end
# Returns +true+ if an error on the attribute with the given message is
# present, or +false+ otherwise. +message+ is treated the same as for +add+.
#
# person.errors.add :age
# person.errors.add :name, :too_long, { count: 25 }
# person.errors.of_kind? :age # => true
# person.errors.of_kind? :name # => false
# person.errors.of_kind? :name, :too_long # => true
# person.errors.of_kind? :name, "is too long (maximum is 25 characters)" # => true
# person.errors.of_kind? :name, :not_too_long # => false
# person.errors.of_kind? :name, "is too long" # => false
def of_kind?(attribute, message = :invalid)
message = message.call if message.respond_to?(:call)
if message.is_a? Symbol
details[attribute.to_sym].map { |e| e[:error] }.include? message
else
self[attribute].include? message
end
end
# Returns all the full error messages in an array.
#
# class Person

View File

@ -209,6 +209,8 @@ class ErrorsTest < ActiveModel::TestCase
person.errors.add(:name, "cannot be blank")
person.errors.add(:name, "is invalid")
assert person.errors.added?(:name, "cannot be blank")
assert person.errors.added?(:name, "is invalid")
assert_not person.errors.added?(:name, "incorrect")
end
test "added? returns false when no errors are present" do
@ -222,7 +224,7 @@ class ErrorsTest < ActiveModel::TestCase
assert_not person.errors.added?(:name, "cannot be blank")
end
test "added? returns false when checking for an error, but not providing message arguments" do
test "added? returns false when checking for an error, but not providing message argument" do
person = Person.new
person.errors.add(:name, "cannot be blank")
assert_not person.errors.added?(:name)
@ -233,6 +235,7 @@ class ErrorsTest < ActiveModel::TestCase
person.errors.add :name, :too_long, count: 25
assert person.errors.added? :name, :too_long, count: 25
assert person.errors.added? :name, "is too long (maximum is 25 characters)"
assert_not person.errors.added? :name, :too_long, count: 24
assert_not person.errors.added? :name, :too_long
assert_not person.errors.added? :name, "is too long"
@ -243,6 +246,81 @@ class ErrorsTest < ActiveModel::TestCase
person = Person.new
person.errors.add(:name, :wrong)
assert_not person.errors.added?(:name, :used)
assert person.errors.added?(:name, :wrong)
end
test "of_kind? returns false when checking for an error, but not providing message argument" do
person = Person.new
person.errors.add(:name, "cannot be blank")
assert_not person.errors.of_kind?(:name)
end
test "of_kind? returns false when checking a nonexisting error and other errors are present for the given attribute" do
person = Person.new
person.errors.add(:name, "is invalid")
assert_not person.errors.of_kind?(:name, "cannot be blank")
end
test "of_kind? returns false when no errors are present" do
person = Person.new
assert_not person.errors.of_kind?(:name)
end
test "of_kind? matches the given message when several errors are present for the same attribute" do
person = Person.new
person.errors.add(:name, "cannot be blank")
person.errors.add(:name, "is invalid")
assert person.errors.of_kind?(:name, "cannot be blank")
assert person.errors.of_kind?(:name, "is invalid")
assert_not person.errors.of_kind?(:name, "incorrect")
end
test "of_kind? defaults message to :invalid" do
person = Person.new
person.errors.add(:name)
assert person.errors.of_kind?(:name)
end
test "of_kind? handles proc messages" do
person = Person.new
message = Proc.new { "cannot be blank" }
person.errors.add(:name, message)
assert person.errors.of_kind?(:name, message)
end
test "of_kind? returns true when string attribute is used with a symbol message" do
person = Person.new
person.errors.add(:name, :blank)
assert person.errors.of_kind?("name", :blank)
end
test "of_kind? handles symbol message" do
person = Person.new
person.errors.add(:name, :blank)
assert person.errors.of_kind?(:name, :blank)
end
test "of_kind? detects indifferent if a specific error was added to the object" do
person = Person.new
person.errors.add(:name, "cannot be blank")
assert person.errors.of_kind?(:name, "cannot be blank")
assert person.errors.of_kind?("name", "cannot be blank")
end
test "of_kind? ignores options" do
person = Person.new
person.errors.add :name, :too_long, count: 25
assert person.errors.of_kind? :name, :too_long
assert person.errors.of_kind? :name, "is too long (maximum is 25 characters)"
end
test "of_kind? returns false when checking for an error by symbol and a different error with same message is present" do
I18n.backend.store_translations("en", errors: { attributes: { name: { wrong: "is wrong", used: "is wrong" } } })
person = Person.new
person.errors.add(:name, :wrong)
assert_not person.errors.of_kind?(:name, :used)
assert person.errors.of_kind?(:name, :wrong)
end
test "size calculates the number of error messages" do