Improve typography of user facing validation messages
With the universal adoption of UTF-8 in browsers, user facing text can use more optimal Unicode typography. In digital and print design, using RIGHT SINGLE QUOTATION MARK (U+2019) is normally preferred over APOSTROPHE (U+0027) in contractions. For details, see the Unicode Standard Section 6.2: https://www.unicode.org/versions/Unicode13.0.0/ch06.pdf > Punctuation Apostrophe. U+2019 right single quotation mark is > preferred where the character is to represent a punctuation mark, as > for contractions: “We’ve been here before.” In this latter case, > U+2019 is also referred to as a punctuation apostrophe.
This commit is contained in:
parent
93b1d3998c
commit
da82e587f2
@ -1347,7 +1347,7 @@ def test_partial_with_form_builder_and_invalid_model_custom_rendering_field_erro
|
||||
get :partial_with_form_builder_and_invalid_model
|
||||
|
||||
assert_equal <<~HTML.strip, @response.body.strip
|
||||
<div class="field_with_errors"><label for="post_title">Title</label> <span class="error">can't be blank</span></div>
|
||||
<div class="field_with_errors"><label for="post_title">Title</label> <span class="error">can’t be blank</span></div>
|
||||
HTML
|
||||
ensure
|
||||
ActionView::Base.field_error_proc = old_proc if old_proc
|
||||
|
@ -20,7 +20,7 @@ def setup
|
||||
super
|
||||
|
||||
@post = Post.new
|
||||
@post.errors.add(:author_name, "can't be empty")
|
||||
@post.errors.add(:author_name, "can’t be empty")
|
||||
@post.errors.add(:body, "foo")
|
||||
@post.errors.add(:category, "must exist")
|
||||
@post.errors.add(:published, "must be accepted")
|
||||
@ -163,7 +163,7 @@ def test_field_error_proc
|
||||
end
|
||||
|
||||
assert_dom_equal(
|
||||
%(<div class="field_with_errors"><input id="post_author_name" name="post[author_name]" type="text" value="" /> <span class="error">can't be empty</span></div>),
|
||||
%(<div class="field_with_errors"><input id="post_author_name" name="post[author_name]" type="text" value="" /> <span class="error">can’t be empty</span></div>),
|
||||
text_field("post", "author_name")
|
||||
)
|
||||
ensure
|
||||
|
@ -276,10 +276,10 @@ def form_with(*, **)
|
||||
@comment = Comment.new
|
||||
def @post.errors
|
||||
Class.new {
|
||||
def [](field); field == "author_name" ? ["can't be empty"] : [] end
|
||||
def [](field); field == "author_name" ? ["can’t be empty"] : [] end
|
||||
def empty?() false end
|
||||
def count() 1 end
|
||||
def full_messages() ["Author name can't be empty"] end
|
||||
def full_messages() ["Author name can’t be empty"] end
|
||||
}.new
|
||||
end
|
||||
def @post.to_key; [123]; end
|
||||
|
@ -110,10 +110,10 @@ def form_for(*)
|
||||
@comment = Comment.new
|
||||
def @post.errors
|
||||
Class.new {
|
||||
def [](field); field == "author_name" ? ["can't be empty"] : [] end
|
||||
def [](field); field == "author_name" ? ["can’t be empty"] : [] end
|
||||
def empty?() false end
|
||||
def count() 1 end
|
||||
def full_messages() ["Author name can't be empty"] end
|
||||
def full_messages() ["Author name can’t be empty"] end
|
||||
}.new
|
||||
end
|
||||
def @post.to_key; [123]; end
|
||||
|
@ -1,3 +1,9 @@
|
||||
* Improve typography of user facing error messages. In English contractions,
|
||||
the Unicode APOSTROPHE (U+0027) is now RIGHT SINGLE QUOTATION MARK
|
||||
(U+2019). For example, “can't be blank” is now “can’t be blank”.
|
||||
|
||||
*Jon Dufresne*
|
||||
|
||||
* Raise `NoMethodError` in `ActiveModel::Type::Value#as_json` to avoid unpredictable
|
||||
results.
|
||||
|
||||
|
@ -285,7 +285,7 @@ def group_by_attribute
|
||||
#
|
||||
# person.errors.add(:name, :blank)
|
||||
# person.errors.messages
|
||||
# # => {:name=>["can't be blank"]}
|
||||
# # => {:name=>["can’t be blank"]}
|
||||
#
|
||||
# person.errors.add(:name, :too_long, count: 25)
|
||||
# person.errors.messages
|
||||
@ -333,7 +333,7 @@ def add(attribute, type = :invalid, **options)
|
||||
#
|
||||
# person.errors.add :name, :blank
|
||||
# person.errors.added? :name, :blank # => true
|
||||
# person.errors.added? :name, "can't be blank" # => true
|
||||
# person.errors.added? :name, "can’t be blank" # => true
|
||||
#
|
||||
# If the error requires options, then it returns +true+ with
|
||||
# the correct options, or +false+ with incorrect or missing options.
|
||||
@ -386,7 +386,7 @@ def of_kind?(attribute, type = :invalid)
|
||||
#
|
||||
# person = Person.create(address: '123 First St.')
|
||||
# person.errors.full_messages
|
||||
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
|
||||
# # => ["Name is too short (minimum is 5 characters)", "Name can’t be blank", "Email can’t be blank"]
|
||||
def full_messages
|
||||
@errors.map(&:full_message)
|
||||
end
|
||||
@ -401,7 +401,7 @@ def full_messages
|
||||
#
|
||||
# person = Person.create()
|
||||
# person.errors.full_messages_for(:name)
|
||||
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank"]
|
||||
# # => ["Name is too short (minimum is 5 characters)", "Name can’t be blank"]
|
||||
def full_messages_for(attribute)
|
||||
where(attribute).map(&:full_message).freeze
|
||||
end
|
||||
@ -415,7 +415,7 @@ def full_messages_for(attribute)
|
||||
#
|
||||
# person = Person.create()
|
||||
# person.errors.messages_for(:name)
|
||||
# # => ["is too short (minimum is 5 characters)", "can't be blank"]
|
||||
# # => ["is too short (minimum is 5 characters)", "can’t be blank"]
|
||||
def messages_for(attribute)
|
||||
where(attribute).map(&:message)
|
||||
end
|
||||
@ -486,7 +486,7 @@ def normalize_arguments(attribute, type, **options)
|
||||
# person = Person.new
|
||||
# person.name = nil
|
||||
# person.valid?
|
||||
# # => ActiveModel::StrictValidationFailed: Name can't be blank
|
||||
# # => ActiveModel::StrictValidationFailed: Name can’t be blank
|
||||
class StrictValidationFailed < StandardError
|
||||
end
|
||||
|
||||
|
@ -10,10 +10,10 @@ en:
|
||||
inclusion: "is not included in the list"
|
||||
exclusion: "is reserved"
|
||||
invalid: "is invalid"
|
||||
confirmation: "doesn't match %{attribute}"
|
||||
confirmation: "doesn’t match %{attribute}"
|
||||
accepted: "must be accepted"
|
||||
empty: "can't be empty"
|
||||
blank: "can't be blank"
|
||||
empty: "can’t be empty"
|
||||
blank: "can’t be blank"
|
||||
present: "must be blank"
|
||||
too_long:
|
||||
one: "is too long (maximum is 1 character)"
|
||||
|
@ -57,7 +57,7 @@ module ClassMethods
|
||||
#
|
||||
# user.save # => false, password required
|
||||
# user.password = "vr00m"
|
||||
# user.save # => false, confirmation doesn't match
|
||||
# user.save # => false, confirmation doesn’t match
|
||||
# user.password_confirmation = "vr00m"
|
||||
# user.save # => true
|
||||
#
|
||||
|
@ -326,7 +326,7 @@ def initialize_dup(other) # :nodoc:
|
||||
#
|
||||
# person = Person.new
|
||||
# person.valid? # => false
|
||||
# person.errors # => #<ActiveModel::Errors:0x007fe603816640 @messages={name:["can't be blank"]}>
|
||||
# person.errors # => #<ActiveModel::Errors:0x007fe603816640 @messages={name:["can’t be blank"]}>
|
||||
def errors
|
||||
@errors ||= Errors.new(self)
|
||||
end
|
||||
|
@ -64,7 +64,7 @@ module HelperMethods
|
||||
# validates_presence_of :password_confirmation, if: :password_changed?
|
||||
#
|
||||
# Configuration options:
|
||||
# * <tt>:message</tt> - A custom error message (default is: "doesn't match
|
||||
# * <tt>:message</tt> - A custom error message (default is: "doesn’t match
|
||||
# <tt>%{translated_attribute_name}</tt>").
|
||||
# * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by
|
||||
# non-text columns (+true+ by default).
|
||||
|
@ -26,7 +26,7 @@ module HelperMethods
|
||||
# <tt>false.blank? # => true</tt>.
|
||||
#
|
||||
# Configuration options:
|
||||
# * <tt>:message</tt> - A custom error message (default is: "can't be blank").
|
||||
# * <tt>:message</tt> - A custom error message (default is: "can’t be blank").
|
||||
#
|
||||
# There is also a list of default options supported by every validator:
|
||||
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
||||
|
@ -144,7 +144,7 @@ def validates(*attributes)
|
||||
# person = Person.new
|
||||
# person.name = ''
|
||||
# person.valid?
|
||||
# # => ActiveModel::StrictValidationFailed: Name can't be blank
|
||||
# # => ActiveModel::StrictValidationFailed: Name can’t be blank
|
||||
def validates!(*attributes)
|
||||
options = attributes.extract_options!
|
||||
options[:strict] = true
|
||||
|
@ -89,7 +89,7 @@ def test_initialize
|
||||
|
||||
test "message with type as a symbol" do
|
||||
error = ActiveModel::Error.new(Person.new, :name, :blank)
|
||||
assert_equal "can't be blank", error.message
|
||||
assert_equal "can’t be blank", error.message
|
||||
end
|
||||
|
||||
test "message with custom interpolation" do
|
||||
@ -178,15 +178,15 @@ def test_initialize
|
||||
|
||||
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
|
||||
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")
|
||||
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
|
||||
assert_equal "name can’t be blank", error.full_message
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -179,7 +179,7 @@ def test_no_key
|
||||
person.errors.add(:name, :blank)
|
||||
|
||||
assert_equal :blank, person.errors.objects.first.type
|
||||
assert_equal ["can't be blank"], person.errors[:name]
|
||||
assert_equal ["can’t be blank"], person.errors[:name]
|
||||
end
|
||||
|
||||
test "add, with type as String" do
|
||||
@ -216,7 +216,7 @@ def test_no_key
|
||||
person.errors.add(:name, type)
|
||||
|
||||
assert_equal :blank, person.errors.objects.first.type
|
||||
assert_equal ["can't be blank"], person.errors[:name]
|
||||
assert_equal ["can’t be blank"], person.errors[:name]
|
||||
end
|
||||
|
||||
test "add an error message on a specific attribute with a defined type" do
|
||||
|
@ -52,14 +52,14 @@ class SecurePasswordTest < ActiveModel::TestCase
|
||||
@user.password = ""
|
||||
assert_not @user.valid?(:create), "user should be invalid"
|
||||
assert_equal 1, @user.errors.count
|
||||
assert_equal ["can't be blank"], @user.errors[:password]
|
||||
assert_equal ["can’t be blank"], @user.errors[:password]
|
||||
end
|
||||
|
||||
test "create a new user with validation and a nil password" do
|
||||
@user.password = nil
|
||||
assert_not @user.valid?(:create), "user should be invalid"
|
||||
assert_equal 1, @user.errors.count
|
||||
assert_equal ["can't be blank"], @user.errors[:password]
|
||||
assert_equal ["can’t be blank"], @user.errors[:password]
|
||||
end
|
||||
|
||||
test "create a new user with validation and password length greater than 72" do
|
||||
@ -75,7 +75,7 @@ class SecurePasswordTest < ActiveModel::TestCase
|
||||
@user.password_confirmation = ""
|
||||
assert_not @user.valid?(:create), "user should be invalid"
|
||||
assert_equal 1, @user.errors.count
|
||||
assert_equal ["doesn't match Password"], @user.errors[:password_confirmation]
|
||||
assert_equal ["doesn’t match Password"], @user.errors[:password_confirmation]
|
||||
end
|
||||
|
||||
test "create a new user with validation and a nil password confirmation" do
|
||||
@ -89,7 +89,7 @@ class SecurePasswordTest < ActiveModel::TestCase
|
||||
@user.password_confirmation = "something else"
|
||||
assert_not @user.valid?(:create), "user should be invalid"
|
||||
assert_equal 1, @user.errors.count
|
||||
assert_equal ["doesn't match Password"], @user.errors[:password_confirmation]
|
||||
assert_equal ["doesn’t match Password"], @user.errors[:password_confirmation]
|
||||
end
|
||||
|
||||
test "resetting password to nil clears the password cache" do
|
||||
@ -134,7 +134,7 @@ class SecurePasswordTest < ActiveModel::TestCase
|
||||
@existing_user.password = nil
|
||||
assert_not @existing_user.valid?(:update), "user should be invalid"
|
||||
assert_equal 1, @existing_user.errors.count
|
||||
assert_equal ["can't be blank"], @existing_user.errors[:password]
|
||||
assert_equal ["can’t be blank"], @existing_user.errors[:password]
|
||||
end
|
||||
|
||||
test "updating an existing user with validation and password length greater than 72" do
|
||||
@ -150,7 +150,7 @@ class SecurePasswordTest < ActiveModel::TestCase
|
||||
@existing_user.password_confirmation = ""
|
||||
assert_not @existing_user.valid?(:update), "user should be invalid"
|
||||
assert_equal 1, @existing_user.errors.count
|
||||
assert_equal ["doesn't match Password"], @existing_user.errors[:password_confirmation]
|
||||
assert_equal ["doesn’t match Password"], @existing_user.errors[:password_confirmation]
|
||||
end
|
||||
|
||||
test "updating an existing user with validation and a nil password confirmation" do
|
||||
@ -164,7 +164,7 @@ class SecurePasswordTest < ActiveModel::TestCase
|
||||
@existing_user.password_confirmation = "something else"
|
||||
assert_not @existing_user.valid?(:update), "user should be invalid"
|
||||
assert_equal 1, @existing_user.errors.count
|
||||
assert_equal ["doesn't match Password"], @existing_user.errors[:password_confirmation]
|
||||
assert_equal ["doesn’t match Password"], @existing_user.errors[:password_confirmation]
|
||||
end
|
||||
|
||||
test "updating an existing user with validation and a correct password challenge" do
|
||||
@ -212,14 +212,14 @@ class SecurePasswordTest < ActiveModel::TestCase
|
||||
@existing_user.password_digest = ""
|
||||
assert_not @existing_user.valid?(:update), "user should be invalid"
|
||||
assert_equal 1, @existing_user.errors.count
|
||||
assert_equal ["can't be blank"], @existing_user.errors[:password]
|
||||
assert_equal ["can’t be blank"], @existing_user.errors[:password]
|
||||
end
|
||||
|
||||
test "updating an existing user with validation and a nil password digest" do
|
||||
@existing_user.password_digest = nil
|
||||
assert_not @existing_user.valid?(:update), "user should be invalid"
|
||||
assert_equal 1, @existing_user.errors.count
|
||||
assert_equal ["can't be blank"], @existing_user.errors[:password]
|
||||
assert_equal ["can’t be blank"], @existing_user.errors[:password]
|
||||
end
|
||||
|
||||
test "setting a blank password should not change an existing password" do
|
||||
|
@ -109,12 +109,12 @@ def @contact.favorite_quote; "Constraints are liberating"; end
|
||||
|
||||
test "should return Hash for errors" do
|
||||
contact = Contact.new
|
||||
contact.errors.add :name, "can't be blank"
|
||||
contact.errors.add :name, "can’t be blank"
|
||||
contact.errors.add :name, "is too short (minimum is 2 characters)"
|
||||
contact.errors.add :age, "must be 16 or over"
|
||||
|
||||
hash = {}
|
||||
hash[:name] = ["can't be blank", "is too short (minimum is 2 characters)"]
|
||||
hash[:name] = ["can’t be blank", "is too short (minimum is 2 characters)"]
|
||||
hash[:age] = ["must be 16 or over"]
|
||||
assert_equal hash.to_json, contact.errors.to_json
|
||||
end
|
||||
|
@ -57,7 +57,7 @@ def test_validates_confirmation_of_for_ruby_class
|
||||
p.karma_confirmation = "None"
|
||||
assert_predicate p, :invalid?
|
||||
|
||||
assert_equal ["doesn't match Karma"], p.errors[:karma_confirmation]
|
||||
assert_equal ["doesn’t match Karma"], p.errors[:karma_confirmation]
|
||||
|
||||
p.karma = "None"
|
||||
assert_predicate p, :valid?
|
||||
@ -70,14 +70,14 @@ def test_title_confirmation_with_i18n_attribute
|
||||
I18n.load_path.clear
|
||||
I18n.backend = I18n::Backend::Simple.new
|
||||
I18n.backend.store_translations("en",
|
||||
errors: { messages: { confirmation: "doesn't match %{attribute}" } },
|
||||
errors: { messages: { confirmation: "doesn’t match %{attribute}" } },
|
||||
activemodel: { attributes: { topic: { title: "Test Title" } } })
|
||||
|
||||
Topic.validates_confirmation_of(:title)
|
||||
|
||||
t = Topic.new("title" => "We should be confirmed", "title_confirmation" => "")
|
||||
assert_predicate t, :invalid?
|
||||
assert_equal ["doesn't match Test Title"], t.errors[:title_confirmation]
|
||||
assert_equal ["doesn’t match Test Title"], t.errors[:title_confirmation]
|
||||
ensure
|
||||
I18n.load_path.replace @old_load_path
|
||||
I18n.backend = @old_backend
|
||||
|
@ -39,7 +39,7 @@ def test_generate_message_invalid_with_custom_message
|
||||
|
||||
# validates_confirmation_of: generate_message(attr_name, :confirmation, message: custom_message)
|
||||
def test_generate_message_confirmation_with_default_message
|
||||
assert_equal "doesn't match Title", @person.errors.generate_message(:title, :confirmation)
|
||||
assert_equal "doesn’t match Title", @person.errors.generate_message(:title, :confirmation)
|
||||
end
|
||||
|
||||
def test_generate_message_confirmation_with_custom_message
|
||||
@ -57,7 +57,7 @@ def test_generate_message_accepted_with_custom_message
|
||||
|
||||
# add_on_empty: generate_message(attr, :empty, message: custom_message)
|
||||
def test_generate_message_empty_with_default_message
|
||||
assert_equal "can't be empty", @person.errors.generate_message(:title, :empty)
|
||||
assert_equal "can’t be empty", @person.errors.generate_message(:title, :empty)
|
||||
end
|
||||
|
||||
def test_generate_message_empty_with_custom_message
|
||||
@ -66,7 +66,7 @@ def test_generate_message_empty_with_custom_message
|
||||
|
||||
# validates_presence_of: generate_message(attr, :blank, message: custom_message)
|
||||
def test_generate_message_blank_with_default_message
|
||||
assert_equal "can't be blank", @person.errors.generate_message(:title, :blank)
|
||||
assert_equal "can’t be blank", @person.errors.generate_message(:title, :blank)
|
||||
end
|
||||
|
||||
def test_generate_message_blank_with_custom_message
|
||||
|
@ -67,9 +67,9 @@ def test_errors_full_messages_on_nested_error_uses_attribute_format
|
||||
})
|
||||
|
||||
person = person_class.new
|
||||
error = ActiveModel::Error.new(person, :gender, "can't be blank")
|
||||
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
|
||||
assert_equal ["Gender can’t be blank"], person.errors.full_messages
|
||||
end
|
||||
|
||||
def test_errors_full_messages_uses_attribute_format
|
||||
|
@ -18,14 +18,14 @@ def test_validate_presences
|
||||
|
||||
t = Topic.new
|
||||
assert_predicate t, :invalid?
|
||||
assert_equal ["can't be blank"], t.errors[:title]
|
||||
assert_equal ["can't be blank"], t.errors[:content]
|
||||
assert_equal ["can’t be blank"], t.errors[:title]
|
||||
assert_equal ["can’t be blank"], t.errors[:content]
|
||||
|
||||
t.title = "something"
|
||||
t.content = " "
|
||||
|
||||
assert_predicate t, :invalid?
|
||||
assert_equal ["can't be blank"], t.errors[:content]
|
||||
assert_equal ["can’t be blank"], t.errors[:content]
|
||||
|
||||
t.content = "like stuff"
|
||||
|
||||
@ -36,8 +36,8 @@ def test_accepts_array_arguments
|
||||
Topic.validates_presence_of %w(title content)
|
||||
t = Topic.new
|
||||
assert_predicate t, :invalid?
|
||||
assert_equal ["can't be blank"], t.errors[:title]
|
||||
assert_equal ["can't be blank"], t.errors[:content]
|
||||
assert_equal ["can’t be blank"], t.errors[:title]
|
||||
assert_equal ["can’t be blank"], t.errors[:content]
|
||||
end
|
||||
|
||||
def test_validates_acceptance_of_with_custom_error_using_quotes
|
||||
@ -53,7 +53,7 @@ def test_validates_presence_of_for_ruby_class
|
||||
p = Person.new
|
||||
assert_predicate p, :invalid?
|
||||
|
||||
assert_equal ["can't be blank"], p.errors[:karma]
|
||||
assert_equal ["can’t be blank"], p.errors[:karma]
|
||||
|
||||
p.karma = "Cold"
|
||||
assert_predicate p, :valid?
|
||||
@ -65,7 +65,7 @@ def test_validates_presence_of_for_ruby_class_with_custom_reader
|
||||
p = CustomReader.new
|
||||
assert_predicate p, :invalid?
|
||||
|
||||
assert_equal ["can't be blank"], p.errors[:karma]
|
||||
assert_equal ["can’t be blank"], p.errors[:karma]
|
||||
|
||||
p[:karma] = "Cold"
|
||||
assert_predicate p, :valid?
|
||||
@ -79,11 +79,11 @@ def test_validates_presence_of_with_allow_nil_option
|
||||
|
||||
t.title = ""
|
||||
assert_predicate t, :invalid?
|
||||
assert_equal ["can't be blank"], t.errors[:title]
|
||||
assert_equal ["can’t be blank"], t.errors[:title]
|
||||
|
||||
t.title = " "
|
||||
assert_predicate t, :invalid?
|
||||
assert_equal ["can't be blank"], t.errors[:title]
|
||||
assert_equal ["can’t be blank"], t.errors[:title]
|
||||
|
||||
t.title = nil
|
||||
assert_predicate t, :valid?
|
||||
|
@ -65,7 +65,7 @@ def test_validates_with_if_as_local_conditions
|
||||
Person.validates :karma, presence: true, email: { if: :condition_is_false }
|
||||
person = Person.new
|
||||
person.valid?
|
||||
assert_equal ["can't be blank"], person.errors[:karma]
|
||||
assert_equal ["can’t be blank"], person.errors[:karma]
|
||||
end
|
||||
|
||||
def test_validates_with_if_as_shared_conditions
|
||||
@ -78,7 +78,7 @@ def test_validates_with_unless_as_local_conditions
|
||||
Person.validates :karma, presence: true, email: { unless: :condition_is_true }
|
||||
person = Person.new
|
||||
person.valid?
|
||||
assert_equal ["can't be blank"], person.errors[:karma]
|
||||
assert_equal ["can’t be blank"], person.errors[:karma]
|
||||
end
|
||||
|
||||
def test_validates_with_unless_shared_conditions
|
||||
|
@ -64,8 +64,8 @@ def test_multiple_errors_per_attr_iteration_with_full_error_composition
|
||||
|
||||
def test_errors_on_nested_attributes_expands_name
|
||||
t = Topic.new
|
||||
t.errors.add("replies.name", "can't be blank")
|
||||
assert_equal ["Replies name can't be blank"], t.errors.full_messages
|
||||
t.errors.add("replies.name", "can’t be blank")
|
||||
assert_equal ["Replies name can’t be blank"], t.errors.full_messages
|
||||
end
|
||||
|
||||
def test_errors_on_base
|
||||
@ -213,8 +213,8 @@ def test_errors_to_json
|
||||
assert_predicate t, :invalid?
|
||||
|
||||
hash = {}
|
||||
hash[:title] = ["can't be blank"]
|
||||
hash[:content] = ["can't be blank"]
|
||||
hash[:title] = ["can’t be blank"]
|
||||
hash[:content] = ["can’t be blank"]
|
||||
assert_equal t.errors.to_json, hash.to_json
|
||||
end
|
||||
|
||||
@ -224,7 +224,7 @@ def test_validation_order
|
||||
|
||||
t = Topic.new("title" => "")
|
||||
assert_predicate t, :invalid?
|
||||
assert_equal "can't be blank", t.errors["title"].first
|
||||
assert_equal "can’t be blank", t.errors["title"].first
|
||||
Topic.validates_presence_of :title, :author_name
|
||||
Topic.validate { errors.add("author_email_address", "will never be valid") }
|
||||
Topic.validates_length_of :title, :content, minimum: 2
|
||||
@ -233,10 +233,10 @@ def test_validation_order
|
||||
assert_predicate t, :invalid?
|
||||
|
||||
assert_equal :title, key = t.errors.attribute_names[0]
|
||||
assert_equal "can't be blank", t.errors[key][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.attribute_names[1]
|
||||
assert_equal "can't be blank", t.errors[key][0]
|
||||
assert_equal "can’t be blank", t.errors[key][0]
|
||||
assert_equal :author_email_address, key = t.errors.attribute_names[2]
|
||||
assert_equal "will never be valid", t.errors[key][0]
|
||||
assert_equal :content, key = t.errors.attribute_names[3]
|
||||
@ -414,7 +414,7 @@ def test_strict_validation_error_message
|
||||
exception = assert_raises(ActiveModel::StrictValidationFailed) do
|
||||
Topic.new.valid?
|
||||
end
|
||||
assert_equal "Title can't be blank", exception.message
|
||||
assert_equal "Title can’t be blank", exception.message
|
||||
end
|
||||
|
||||
def test_does_not_modify_options_argument
|
||||
|
@ -359,7 +359,7 @@ def create(attributes = {}, &block)
|
||||
# end
|
||||
#
|
||||
# person.pets.create!(name: nil)
|
||||
# # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
||||
# # => ActiveRecord::RecordInvalid: Validation failed: Name can’t be blank
|
||||
def create!(attributes = {}, &block)
|
||||
@association.create!(attributes, &block)
|
||||
end
|
||||
|
@ -2828,7 +2828,7 @@ def test_association_with_rewhere_doesnt_set_inverse_instance_key
|
||||
|
||||
assert_predicate pirate, :valid?
|
||||
assert_not pirate.valid?(:conference)
|
||||
assert_equal "can't be blank", ship.errors[:name].first
|
||||
assert_equal "can’t be blank", ship.errors[:name].first
|
||||
end
|
||||
|
||||
test "association with instance dependent scope" do
|
||||
|
@ -529,8 +529,8 @@ def test_errors_should_be_indexed_when_global_flag_is_set
|
||||
assert_not_predicate invalid_electron, :valid?
|
||||
assert_predicate valid_electron, :valid?
|
||||
assert_not_predicate molecule, :valid?
|
||||
assert_equal ["can't be blank"], molecule.errors["electrons[1].name"]
|
||||
assert_not_equal ["can't be blank"], molecule.errors["electrons.name"]
|
||||
assert_equal ["can’t be blank"], molecule.errors["electrons[1].name"]
|
||||
assert_not_equal ["can’t be blank"], molecule.errors["electrons.name"]
|
||||
ensure
|
||||
ActiveRecord.index_nested_attribute_errors = old_attribute_config
|
||||
end
|
||||
@ -1339,7 +1339,7 @@ def test_should_not_ignore_different_error_messages_on_the_same_attribute
|
||||
@pirate.ship.name = ""
|
||||
@pirate.catchphrase = nil
|
||||
assert_predicate @pirate, :invalid?
|
||||
assert_equal ["can't be blank", "is invalid"], @pirate.errors[:"ship.name"]
|
||||
assert_equal ["can’t be blank", "is invalid"], @pirate.errors[:"ship.name"]
|
||||
ensure
|
||||
Ship._validators = old_validators if old_validators
|
||||
Ship._validate_callbacks = old_callbacks if old_callbacks
|
||||
@ -1638,7 +1638,7 @@ def test_should_automatically_validate_the_associated_models
|
||||
@pirate.public_send(@association_name).each { |child| child.name = "" }
|
||||
|
||||
assert_not_predicate @pirate, :valid?
|
||||
assert_equal ["can't be blank"], @pirate.errors["#{@association_name}.name"]
|
||||
assert_equal ["can’t be blank"], @pirate.errors["#{@association_name}.name"]
|
||||
assert_empty @pirate.errors[@association_name]
|
||||
end
|
||||
|
||||
@ -1646,7 +1646,7 @@ def test_should_not_use_default_invalid_error_on_associated_models
|
||||
@pirate.public_send(@association_name).build(name: "")
|
||||
|
||||
assert_not_predicate @pirate, :valid?
|
||||
assert_equal ["can't be blank"], @pirate.errors["#{@association_name}.name"]
|
||||
assert_equal ["can’t be blank"], @pirate.errors["#{@association_name}.name"]
|
||||
assert_empty @pirate.errors[@association_name]
|
||||
end
|
||||
|
||||
@ -1670,7 +1670,7 @@ def test_should_merge_errors_on_the_associated_models_onto_the_parent_even_if_it
|
||||
@pirate.catchphrase = nil
|
||||
|
||||
assert_not_predicate @pirate, :valid?
|
||||
assert_equal ["can't be blank"], @pirate.errors["#{@association_name}.name"]
|
||||
assert_equal ["can’t be blank"], @pirate.errors["#{@association_name}.name"]
|
||||
assert_predicate @pirate.errors[:catchphrase], :any?
|
||||
end
|
||||
|
||||
|
@ -1104,7 +1104,7 @@ def setup
|
||||
part = ShipPart.new(name: "Stern", ship_attributes: { name: nil })
|
||||
|
||||
assert_not_predicate part, :valid?
|
||||
assert_equal ["Ship name can't be blank"], part.errors.full_messages
|
||||
assert_equal ["Ship name can’t be blank"], part.errors.full_messages
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -48,7 +48,7 @@ def test_generate_message_taken_with_custom_message
|
||||
topic = Topic.new
|
||||
topic.errors.add(:title, :invalid)
|
||||
topic.errors.add(:title, :blank)
|
||||
assert_equal "Validation failed: Title is invalid, Title can't be blank", ActiveRecord::RecordInvalid.new(topic).message
|
||||
assert_equal "Validation failed: Title is invalid, Title can’t be blank", ActiveRecord::RecordInvalid.new(topic).message
|
||||
end
|
||||
|
||||
test "RecordInvalid exception translation falls back to the :errors namespace" do
|
||||
|
@ -364,7 +364,7 @@ irb> user = User.new
|
||||
irb> user.save
|
||||
=> false
|
||||
irb> user.save!
|
||||
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
||||
ActiveRecord::RecordInvalid: Validation failed: Name can’t be blank
|
||||
```
|
||||
|
||||
You can learn more about validations in the [Active Record Validations
|
||||
|
@ -2088,7 +2088,7 @@ to your `Customer` model. If you try to create a new `Customer` without passing
|
||||
|
||||
```irb
|
||||
irb> Customer.find_or_create_by!(first_name: 'Andy')
|
||||
ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank
|
||||
ActiveRecord::RecordInvalid: Validation failed: Orders count can’t be blank
|
||||
```
|
||||
|
||||
[`find_or_create_by!`]: https://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-find_or_create_by-21
|
||||
|
@ -205,21 +205,21 @@ irb> p.errors.size
|
||||
irb> p.valid?
|
||||
=> false
|
||||
irb> p.errors.objects.first.full_message
|
||||
=> "Name can't be blank"
|
||||
=> "Name can’t be blank"
|
||||
|
||||
irb> p = Person.create
|
||||
=> #<Person id: nil, name: nil>
|
||||
irb> p.errors.objects.first.full_message
|
||||
=> "Name can't be blank"
|
||||
=> "Name can’t be blank"
|
||||
|
||||
irb> p.save
|
||||
=> false
|
||||
|
||||
irb> p.save!
|
||||
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
||||
ActiveRecord::RecordInvalid: Validation failed: Name can’t be blank
|
||||
|
||||
irb> Person.create!
|
||||
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
|
||||
ActiveRecord::RecordInvalid: Validation failed: Name can’t be blank
|
||||
```
|
||||
|
||||
[`invalid?`][] is the inverse of `valid?`. It triggers your validations,
|
||||
@ -648,7 +648,7 @@ validates :boolean_field_name, exclusion: [nil]
|
||||
By using one of these validations, you will ensure the value will NOT be `nil`
|
||||
which would result in a `NULL` value in most cases.
|
||||
|
||||
The default error message is _"can't be blank"_.
|
||||
The default error message is _"can’t be blank"_.
|
||||
|
||||
[`Object#blank?`]: https://api.rubyonrails.org/classes/Object.html#method-i-blank-3F
|
||||
|
||||
@ -1086,7 +1086,7 @@ irb> book.valid?
|
||||
irb> book.valid?(:ensure_title)
|
||||
=> false
|
||||
irb> book.errors.messages
|
||||
=> {:title=>["can't be blank"]}
|
||||
=> {:title=>["can’t be blank"]}
|
||||
```
|
||||
|
||||
When triggered by an explicit context, validations are run for that context,
|
||||
@ -1105,7 +1105,7 @@ irb> person = Person.new
|
||||
irb> person.valid?(:account_setup)
|
||||
=> false
|
||||
irb> person.errors.messages
|
||||
=> {:email=>["has already been taken"], :age=>["is not a number"], :name=>["can't be blank"]}
|
||||
=> {:email=>["has already been taken"], :age=>["is not a number"], :name=>["can’t be blank"]}
|
||||
```
|
||||
|
||||
We will cover more use-cases for `on:` in the [callbacks guide](active_record_callbacks.html).
|
||||
@ -1124,7 +1124,7 @@ end
|
||||
|
||||
```irb
|
||||
irb> Person.new.valid?
|
||||
ActiveModel::StrictValidationFailed: Name can't be blank
|
||||
ActiveModel::StrictValidationFailed: Name can’t be blank
|
||||
```
|
||||
|
||||
There is also the ability to pass a custom exception to the `:strict` option.
|
||||
@ -1137,7 +1137,7 @@ end
|
||||
|
||||
```irb
|
||||
irb> Person.new.valid?
|
||||
TokenGenerationException: Token can't be blank
|
||||
TokenGenerationException: Token can’t be blank
|
||||
```
|
||||
|
||||
Conditional Validation
|
||||
@ -1394,7 +1394,7 @@ irb> person = Person.new
|
||||
irb> person.valid?
|
||||
=> false
|
||||
irb> person.errors.full_messages
|
||||
=> ["Name can't be blank", "Name is too short (minimum is 3 characters)"]
|
||||
=> ["Name can’t be blank", "Name is too short (minimum is 3 characters)"]
|
||||
|
||||
irb> person = Person.new(name: "John Doe")
|
||||
irb> person.valid?
|
||||
@ -1441,7 +1441,7 @@ irb> person = Person.new
|
||||
irb> person.valid?
|
||||
=> false
|
||||
irb> person.errors[:name]
|
||||
=> ["can't be blank", "is too short (minimum is 3 characters)"]
|
||||
=> ["can’t be blank", "is too short (minimum is 3 characters)"]
|
||||
```
|
||||
|
||||
### `errors.where` and Error Object
|
||||
|
@ -931,13 +931,13 @@ irb> person = Person.new.tap(&:valid?)
|
||||
|
||||
irb> person.errors.full_messages
|
||||
=> [
|
||||
"Invalid Name (can't be blank)",
|
||||
"Invalid Name (can’t be blank)",
|
||||
"Please fill in your Age"
|
||||
]
|
||||
|
||||
irb> person.errors.messages
|
||||
=> {
|
||||
:name => ["can't be blank"],
|
||||
:name => ["can’t be blank"],
|
||||
:age => ["Please fill in your Age"]
|
||||
}
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user