diff options
Diffstat (limited to 'activemodel')
-rw-r--r-- | activemodel/CHANGELOG.md | 25 | ||||
-rw-r--r-- | activemodel/lib/active_model/errors.rb | 7 | ||||
-rw-r--r-- | activemodel/test/cases/validations/i18n_validation_test.rb | 59 |
3 files changed, 76 insertions, 15 deletions
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index 0b2fa37787..6048911217 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -6,17 +6,17 @@ * Fix `ActiveModel::Serializers::JSON#as_json` method for timestamps. - Before: - ``` - contact = Contact.new(created_at: Time.utc(2006, 8, 1)) - contact.as_json["created_at"] # => 2006-08-01 00:00:00 UTC - ``` - - After: - ``` - contact = Contact.new(created_at: Time.utc(2006, 8, 1)) - contact.as_json["created_at"] # => "2006-08-01T00:00:00.000Z" - ``` + Before: + ``` + contact = Contact.new(created_at: Time.utc(2006, 8, 1)) + contact.as_json["created_at"] # => 2006-08-01 00:00:00 UTC + ``` + + After: + ``` + contact = Contact.new(created_at: Time.utc(2006, 8, 1)) + contact.as_json["created_at"] # => "2006-08-01T00:00:00.000Z" + ``` *Bogdan Gusiev* @@ -25,6 +25,7 @@ change. There is a new method `#authenticate_XXX` where XXX is the configured attribute name, making the existing `#authenticate` now an alias for this when the attribute is the default 'password'. + Example: class User < ActiveRecord::Base @@ -36,7 +37,7 @@ user.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uX..." user.authenticate_recovery_password('42password') # => user - *Unathi Chonco* + *Unathi Chonco* * Add `config.active_model.i18n_full_message` in order to control whether the `full_message` error format can be overridden at the attribute or model diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index edc30ee64d..af94d52d45 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -379,9 +379,11 @@ module ActiveModel # * <tt>errors.format</tt> def full_message(attribute, message) return message if attribute == :base + attribute = attribute.to_s if self.class.i18n_full_message && @base.class.respond_to?(:i18n_scope) - parts = attribute.to_s.split(".") + attribute = attribute.remove(/\[\d\]/) + parts = attribute.split(".") attribute_name = parts.pop namespace = parts.join("/") unless parts.empty? attributes_scope = "#{@base.class.i18n_scope}.errors.models" @@ -410,8 +412,9 @@ module ActiveModel defaults << :"errors.format" defaults << "%{attribute} %{message}" - attr_name = attribute.to_s.tr(".", "_").humanize + attr_name = attribute.tr(".", "_").humanize attr_name = @base.class.human_attribute_name(attribute, default: attr_name) + I18n.t(defaults.shift, default: defaults, attribute: attr_name, diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index 1c62e750de..ccb565c5bd 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -35,7 +35,7 @@ class I18nValidationTest < ActiveModel::TestCase def test_errors_full_messages_translates_human_attribute_name_for_model_attributes @person.errors.add(:name, "not found") - assert_called_with(Person, :human_attribute_name, [:name, default: "Name"], returns: "Person's name") do + assert_called_with(Person, :human_attribute_name, ["name", default: "Name"], returns: "Person's name") do assert_equal ["Person's name not found"], @person.errors.full_messages end end @@ -101,6 +101,63 @@ class I18nValidationTest < ActiveModel::TestCase assert_equal "cannot be blank", person.errors.full_message(:'contacts/addresses.country', "cannot be blank") end + def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_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[0]/addresses[0].street', "cannot be blank") + assert_equal "Contacts/addresses country cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank") + end + + def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_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[0]/addresses[0].street', "cannot be blank") + assert_equal "cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank") + end + + def test_errors_full_messages_with_indexed_deeply_nested_attributes_and_i18n_attribute_name + ActiveModel::Errors.i18n_full_message = true + + I18n.backend.store_translations("en", activemodel: { + attributes: { 'person/contacts/addresses': { country: "Country" } } + }) + + person = Person.new + assert_equal "Contacts/addresses street cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].street', "cannot be blank") + assert_equal "Country cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank") + end + + def test_errors_full_messages_with_indexed_deeply_nested_attributes_without_i18n_config + ActiveModel::Errors.i18n_full_message = false + + I18n.backend.store_translations("en", activemodel: { + errors: { models: { 'person/contacts/addresses': { attributes: { street: { format: "%{message}" } } } } } }) + + person = Person.new + assert_equal "Contacts[0]/addresses[0] street cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].street', "cannot be blank") + assert_equal "Contacts[0]/addresses[0] country cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank") + end + + def test_errors_full_messages_with_i18n_attribute_name_without_i18n_config + ActiveModel::Errors.i18n_full_message = false + + I18n.backend.store_translations("en", activemodel: { + attributes: { 'person/contacts[0]/addresses[0]': { country: "Country" } } + }) + + person = Person.new + assert_equal "Contacts[0]/addresses[0] street cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].street', "cannot be blank") + assert_equal "Country cannot be blank", person.errors.full_message(:'contacts[0]/addresses[0].country', "cannot be blank") + end + # ActiveModel::Validations # A set of common cases for ActiveModel::Validations message generation that |