mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #32956 from Shopify/i18n_activemodel_errors_full_message
Allow to override the full_message error format
This commit is contained in:
commit
d3f659e526
5 changed files with 135 additions and 2 deletions
|
@ -62,6 +62,11 @@ module ActiveModel
|
|||
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
|
||||
MESSAGE_OPTIONS = [:message]
|
||||
|
||||
class << self
|
||||
attr_accessor :i18n_full_message # :nodoc:
|
||||
end
|
||||
self.i18n_full_message = false
|
||||
|
||||
attr_reader :messages, :details
|
||||
|
||||
# Pass in the instance of the object that is using the errors object.
|
||||
|
@ -364,12 +369,51 @@ module ActiveModel
|
|||
# Returns a full message for a given attribute.
|
||||
#
|
||||
# person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
|
||||
#
|
||||
# The `"%{attribute} %{message}"` error format can be overridden with either
|
||||
#
|
||||
# * <tt>activemodel.errors.models.person/contacts/addresses.attributes.street.format</tt>
|
||||
# * <tt>activemodel.errors.models.person/contacts/addresses.format</tt>
|
||||
# * <tt>activemodel.errors.models.person.attributes.name.format</tt>
|
||||
# * <tt>activemodel.errors.models.person.format</tt>
|
||||
# * <tt>errors.format</tt>
|
||||
def full_message(attribute, message)
|
||||
return message if attribute == :base
|
||||
|
||||
if self.class.i18n_full_message && @base.class.respond_to?(:i18n_scope)
|
||||
parts = attribute.to_s.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.to_s.tr(".", "_").humanize
|
||||
attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
|
||||
I18n.t(:"errors.format",
|
||||
default: "%{attribute} %{message}",
|
||||
I18n.t(defaults.shift,
|
||||
default: defaults,
|
||||
attribute: attr_name,
|
||||
message: message)
|
||||
end
|
||||
|
|
|
@ -7,8 +7,14 @@ module ActiveModel
|
|||
class Railtie < Rails::Railtie # :nodoc:
|
||||
config.eager_load_namespaces << ActiveModel
|
||||
|
||||
config.active_model = ActiveSupport::OrderedOptions.new
|
||||
|
||||
initializer "active_model.secure_password" do
|
||||
ActiveModel::SecurePassword.min_cost = Rails.env.test?
|
||||
end
|
||||
|
||||
initializer "active_model.i18n_full_message" do
|
||||
ActiveModel::Errors.i18n_full_message = config.active_model.delete(:i18n_full_message) || false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,4 +31,24 @@ class RailtieTest < ActiveModel::TestCase
|
|||
|
||||
assert_equal true, ActiveModel::SecurePassword.min_cost
|
||||
end
|
||||
|
||||
test "i18n full message defaults to false" do
|
||||
@app.initialize!
|
||||
|
||||
assert_equal false, ActiveModel::Errors.i18n_full_message
|
||||
end
|
||||
|
||||
test "i18n full message can be disabled" do
|
||||
@app.config.active_model.i18n_full_message = false
|
||||
@app.initialize!
|
||||
|
||||
assert_equal false, ActiveModel::Errors.i18n_full_message
|
||||
end
|
||||
|
||||
test "i18n full message can be enabled" do
|
||||
@app.config.active_model.i18n_full_message = true
|
||||
@app.initialize!
|
||||
|
||||
assert_equal true, ActiveModel::Errors.i18n_full_message
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,6 +12,9 @@ class I18nValidationTest < ActiveModel::TestCase
|
|||
I18n.load_path.clear
|
||||
I18n.backend = I18n::Backend::Simple.new
|
||||
I18n.backend.store_translations("en", errors: { messages: { custom: nil } })
|
||||
|
||||
@original_i18n_full_message = ActiveModel::Errors.i18n_full_message
|
||||
ActiveModel::Errors.i18n_full_message = true
|
||||
end
|
||||
|
||||
def teardown
|
||||
|
@ -19,6 +22,7 @@ class I18nValidationTest < ActiveModel::TestCase
|
|||
I18n.load_path.replace @old_load_path
|
||||
I18n.backend = @old_backend
|
||||
I18n.backend.reload!
|
||||
ActiveModel::Errors.i18n_full_message = @original_i18n_full_message
|
||||
end
|
||||
|
||||
def test_full_message_encoding
|
||||
|
@ -42,6 +46,61 @@ class I18nValidationTest < ActiveModel::TestCase
|
|||
assert_equal ["Field Name empty"], @person.errors.full_messages
|
||||
end
|
||||
|
||||
def test_errors_full_messages_doesnt_use_attribute_format_without_config
|
||||
ActiveModel::Errors.i18n_full_message = false
|
||||
|
||||
I18n.backend.store_translations("en", activemodel: {
|
||||
errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } })
|
||||
|
||||
person = Person.new
|
||||
assert_equal "Name cannot be blank", person.errors.full_message(:name, "cannot be blank")
|
||||
assert_equal "Name test cannot be blank", person.errors.full_message(:name_test, "cannot be blank")
|
||||
end
|
||||
|
||||
def test_errors_full_messages_uses_attribute_format
|
||||
ActiveModel::Errors.i18n_full_message = true
|
||||
|
||||
I18n.backend.store_translations("en", activemodel: {
|
||||
errors: { models: { person: { attributes: { name: { format: "%{message}" } } } } } })
|
||||
|
||||
person = Person.new
|
||||
assert_equal "cannot be blank", person.errors.full_message(:name, "cannot be blank")
|
||||
assert_equal "Name test cannot be blank", person.errors.full_message(:name_test, "cannot be blank")
|
||||
end
|
||||
|
||||
def test_errors_full_messages_uses_model_format
|
||||
ActiveModel::Errors.i18n_full_message = true
|
||||
|
||||
I18n.backend.store_translations("en", activemodel: {
|
||||
errors: { models: { person: { format: "%{message}" } } } })
|
||||
|
||||
person = Person.new
|
||||
assert_equal "cannot be blank", person.errors.full_message(:name, "cannot be blank")
|
||||
assert_equal "cannot be blank", person.errors.full_message(:name_test, "cannot be blank")
|
||||
end
|
||||
|
||||
def test_errors_full_messages_uses_deeply_nested_model_attributes_format
|
||||
ActiveModel::Errors.i18n_full_message = true
|
||||
|
||||
I18n.backend.store_translations("en", activemodel: {
|
||||
errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } })
|
||||
|
||||
person = Person.new
|
||||
assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.street', "cannot be blank")
|
||||
assert_equal "Contacts/addresses country cannot be blank", person.errors.full_message(:'contacts/addresses.country', "cannot be blank")
|
||||
end
|
||||
|
||||
def test_errors_full_messages_uses_deeply_nested_model_model_format
|
||||
ActiveModel::Errors.i18n_full_message = true
|
||||
|
||||
I18n.backend.store_translations("en", activemodel: {
|
||||
errors: { models: { 'person/contacts/addresses': { format: "%{message}" } } } })
|
||||
|
||||
person = Person.new
|
||||
assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.street', "cannot be blank")
|
||||
assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.country', "cannot be blank")
|
||||
end
|
||||
|
||||
# ActiveModel::Validations
|
||||
|
||||
# A set of common cases for ActiveModel::Validations message generation that
|
||||
|
|
|
@ -305,6 +305,10 @@ All these configuration options are delegated to the `I18n` library.
|
|||
config.i18n.fallbacks.map = { az: :tr, da: [:de, :en] }
|
||||
```
|
||||
|
||||
### Configuring Active Model
|
||||
|
||||
* `config.active_model.i18n_full_message` is a boolean value which controls whether the `full_message` error format can be overridden at the attribute or model level in the locale files
|
||||
|
||||
### Configuring Active Record
|
||||
|
||||
`config.active_record` includes a variety of configuration options:
|
||||
|
|
Loading…
Reference in a new issue