From a4064ab431845d122c1414c684d2abc60d888571 Mon Sep 17 00:00:00 2001 From: Anton Bangratz Date: Tue, 14 Sep 2010 16:58:30 +0200 Subject: [PATCH] Full messages and nested attributes I18n When using nested attributes, the lookup for names in full messages is just using 'humanize' after turning the '.' separator into '_'. This change makes sure that the correct model is looked up and then model_name.human and human_attribute_name are called for the model and the attribute, after checking that the 'model' exists as constant and responds to those methods. --- activemodel/lib/active_model/errors.rb | 18 +++++++++++++++++- .../test/cases/validations/i18n_validation_test.rb | 10 ++++++++++ activemodel/test/models/address.rb | 11 +++++++++++ 3 files changed, 38 insertions(+), 1 deletions(-) create mode 100644 activemodel/test/models/address.rb diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb index e9a61da..d3cf833 100644 --- a/activemodel/lib/active_model/errors.rb +++ b/activemodel/lib/active_model/errors.rb @@ -224,7 +224,8 @@ module ActiveModel if attribute == :base messages.each {|m| full_messages << m } else - attr_name = attribute.to_s.gsub('.', '_').humanize + attr_name = convert_name(attribute.to_s) + attr_name ||= attribute.to_s.gsub('.', '_').humanize attr_name = @base.class.human_attribute_name(attribute, :default => attr_name) options = { :default => "%{attribute} %{message}", :attribute => attr_name } @@ -237,6 +238,21 @@ module ActiveModel full_messages end + # Converts an attribute name to the real attribute name (especially for nested attributes) + # + def convert_name(name) + default = nil + if name =~ /(.+)\.(.+)/ + base_name = $1 + attribute = $2 + base = ActiveSupport::Dependencies.constantize(base_name.camelize) + if (base.respond_to? :model_name) + default = "#{base.model_name.human} #{base.human_attribute_name(attribute.to_sym, :default => attribute.humanize)}" + end + end + default + end + # Translates an error message in its default scope # (activemodel.errors.messages). # diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb index e9f0e43..b64afa7 100644 --- a/activemodel/test/cases/validations/i18n_validation_test.rb +++ b/activemodel/test/cases/validations/i18n_validation_test.rb @@ -2,6 +2,7 @@ require "cases/helper" require 'models/person' +require 'models/address' class I18nValidationTest < ActiveModel::TestCase @@ -55,6 +56,15 @@ class I18nValidationTest < ActiveModel::TestCase assert_equal ["Person's name not found"], @person.errors.full_messages end + def test_errors_full_messages_translates_human_attribute_name_for_nested_model_attributes + @person.errors.add('address.street', 'empty') + Address.expects(:human_attribute_name).with(:street, :default => 'Street').once.returns("Street") + model_name = mock() + model_name.expects(:human).returns("Address'") + Address.expects(:model_name).returns(model_name) + assert_equal ["Address' Street empty"], @person.errors.full_messages + end + def test_errors_full_messages_uses_format I18n.backend.store_translations('en', :errors => {:format => "Field %{attribute} %{message}"}) @person.errors.add('name', 'empty') diff --git a/activemodel/test/models/address.rb b/activemodel/test/models/address.rb new file mode 100644 index 0000000..938416b --- /dev/null +++ b/activemodel/test/models/address.rb @@ -0,0 +1,11 @@ + +class Address + include ActiveModel::Validations + extend ActiveModel::Translation + + + def condition_is_true + true + end +end + -- 1.7.1