aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel
diff options
context:
space:
mode:
authorMartin Larochelle <martin.larochelle@shopify.com>2018-05-17 08:39:31 -0400
committerMartin Larochelle <martin.larochelle@shopify.com>2018-05-22 16:31:30 -0400
commit7d09874a71ecceb929a99f914b703adc16d80e83 (patch)
tree55f840e2ea961ceb203c335729ba4d4e1cb650a5 /activemodel
parent5003d5996a3d29d6614ccf714ad05f911aa30cff (diff)
downloadrails-7d09874a71ecceb929a99f914b703adc16d80e83.tar.gz
rails-7d09874a71ecceb929a99f914b703adc16d80e83.tar.bz2
rails-7d09874a71ecceb929a99f914b703adc16d80e83.zip
Allow to override the full_message error format
Diffstat (limited to 'activemodel')
-rw-r--r--activemodel/lib/active_model/errors.rb43
-rw-r--r--activemodel/test/cases/validations/i18n_validation_test.rb36
2 files changed, 77 insertions, 2 deletions
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index 275e3f1313..e813629855 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -364,12 +364,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 @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
diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb
index 9cfe189d0e..ea462d9e07 100644
--- a/activemodel/test/cases/validations/i18n_validation_test.rb
+++ b/activemodel/test/cases/validations/i18n_validation_test.rb
@@ -42,6 +42,42 @@ class I18nValidationTest < ActiveModel::TestCase
assert_equal ["Field Name empty"], @person.errors.full_messages
end
+ def test_errors_full_messages_uses_attribute_format
+ 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
+ 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
+ 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
+ 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