From 45d41f0dadd9fa171f306ff356770c4492726f30 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Thu, 19 Jun 2008 16:25:27 +0200 Subject: integrating I18n into Rails --- activerecord/lib/active_record.rb | 2 + activerecord/lib/active_record/lang/en-US.rb | 25 ++ activerecord/lib/active_record/validations.rb | 184 ++++---- activerecord/test/cases/validations_i18n_test.rb | 539 +++++++++++++++++++++++ 4 files changed, 674 insertions(+), 76 deletions(-) create mode 100644 activerecord/lib/active_record/lang/en-US.rb create mode 100644 activerecord/test/cases/validations_i18n_test.rb (limited to 'activerecord') diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index d4f7170305..b379bd26f8 100755 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -80,3 +80,5 @@ end require 'active_record/connection_adapters/abstract_adapter' require 'active_record/schema_dumper' + +require 'active_record/lang/en-US.rb' diff --git a/activerecord/lib/active_record/lang/en-US.rb b/activerecord/lib/active_record/lang/en-US.rb new file mode 100644 index 0000000000..7c3bcfd85e --- /dev/null +++ b/activerecord/lib/active_record/lang/en-US.rb @@ -0,0 +1,25 @@ +I18n.backend.add_translations :'en-US', { + :active_record => { + :error_messages => { + :inclusion => "is not included in the list", + :exclusion => "is reserved", + :invalid => "is invalid", + :confirmation => "doesn't match confirmation", + :accepted => "must be accepted", + :empty => "can't be empty", + :blank => "can't be blank", + :too_long => "is too long (maximum is {{count}} characters)", + :too_short => "is too short (minimum is {{count}} characters)", + :wrong_length => "is the wrong length (should be {{count}} characters)", + :taken => "has already been taken", + :not_a_number => "is not a number", + :greater_than => "must be greater than {{count}}", + :greater_than_or_equal_to => "must be greater than or equal to {{count}}", + :equal_to => "must be equal to {{count}}", + :less_than => "must be less than {{count}}", + :less_than_or_equal_to => "must be less than or equal to {{count}}", + :odd => "must be odd", + :even => "must be even" + } + } +} \ No newline at end of file diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index c4e370d017..f54fb80137 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -23,30 +23,30 @@ module ActiveRecord @base, @errors = base, {} end - @@default_error_messages = { - :inclusion => "is not included in the list", - :exclusion => "is reserved", - :invalid => "is invalid", - :confirmation => "doesn't match confirmation", - :accepted => "must be accepted", - :empty => "can't be empty", - :blank => "can't be blank", - :too_long => "is too long (maximum is %d characters)", - :too_short => "is too short (minimum is %d characters)", - :wrong_length => "is the wrong length (should be %d characters)", - :taken => "has already been taken", - :not_a_number => "is not a number", - :greater_than => "must be greater than %d", - :greater_than_or_equal_to => "must be greater than or equal to %d", - :equal_to => "must be equal to %d", - :less_than => "must be less than %d", - :less_than_or_equal_to => "must be less than or equal to %d", - :odd => "must be odd", - :even => "must be even" - } - - # Holds a hash with all the default error messages that can be replaced by your own copy or localizations. - cattr_accessor :default_error_messages + # @@default_error_messages = { + # :inclusion => "is not included in the list", + # :exclusion => "is reserved", + # :invalid => "is invalid", + # :confirmation => "doesn't match confirmation", + # :accepted => "must be accepted", + # :empty => "can't be empty", + # :blank => "can't be blank", + # :too_long => "is too long (maximum is %d characters)", + # :too_short => "is too short (minimum is %d characters)", + # :wrong_length => "is the wrong length (should be %d characters)", + # :taken => "has already been taken", + # :not_a_number => "is not a number", + # :greater_than => "must be greater than %d", + # :greater_than_or_equal_to => "must be greater than or equal to %d", + # :equal_to => "must be equal to %d", + # :less_than => "must be less than %d", + # :less_than_or_equal_to => "must be less than or equal to %d", + # :odd => "must be odd", + # :even => "must be even" + # } + # + # # Holds a hash with all the default error messages that can be replaced by your own copy or localizations. + # cattr_accessor :default_error_messages # Adds an error to the base object instead of any particular attribute. This is used @@ -61,27 +61,34 @@ module ActiveRecord # for the same attribute and ensure that this error object returns false when asked if empty?. More than one # error can be added to the same +attribute+ in which case an array will be returned on a call to on(attribute). # If no +msg+ is supplied, "invalid" is assumed. - def add(attribute, msg = @@default_error_messages[:invalid]) - @errors[attribute.to_s] = [] if @errors[attribute.to_s].nil? - @errors[attribute.to_s] << msg - end + def add(attribute, message = nil) + message ||= :"active_record.error_messages.invalid".t + @errors[attribute.to_s] ||= [] + @errors[attribute.to_s] << message + end # Will add an error message to each of the attributes in +attributes+ that is empty. - def add_on_empty(attributes, msg = @@default_error_messages[:empty]) + def add_on_empty(attributes, custom_message = nil) for attr in [attributes].flatten value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s] - is_empty = value.respond_to?("empty?") ? value.empty? : false - add(attr, msg) unless !value.nil? && !is_empty + is_empty = value.respond_to?("empty?") ? value.empty? : false + add(attr, generate_message(attr, :empty, :default => custom_message)) unless !value.nil? && !is_empty end end # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?). - def add_on_blank(attributes, msg = @@default_error_messages[:blank]) + def add_on_blank(attributes, custom_message = nil) for attr in [attributes].flatten value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s] - add(attr, msg) if value.blank? + add(attr, generate_message(attr, :blank, :default => custom_message)) if value.blank? end end + + def generate_message(attr, key, options = {}) + scope = [:active_record, :error_messages] + key.t(options.merge(:scope => scope + [:custom, @base.class.name.downcase, attr])) || + key.t(options.merge(:scope => scope)) + end # Returns true if the specified +attribute+ has errors associated with it. # @@ -166,22 +173,25 @@ module ActiveRecord # company = Company.create(:address => '123 First St.') # company.errors.full_messages # => # ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"] - def full_messages + def full_messages(options = {}) full_messages = [] + locale = options[:locale] @errors.each_key do |attr| - @errors[attr].each do |msg| - next if msg.nil? - + @errors[attr].each do |message| + next unless message + if attr == "base" - full_messages << msg + full_messages << message else - full_messages << @base.class.human_attribute_name(attr) + " " + msg + key = :"active_record.human_attribute_names.#{@base.class.name.underscore.to_sym}.#{attr}" + attr_name = key.t(locale) || @base.class.human_attribute_name(attr) + full_messages << attr_name + " " + message end end end full_messages - end + end # Returns true if no errors have been added. def empty? @@ -388,15 +398,18 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_confirmation_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save } + configuration = { :on => :save } configuration.update(attr_names.extract_options!) attr_accessor(*(attr_names.map { |n| "#{n}_confirmation" })) validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message]) unless record.send("#{attr_name}_confirmation").nil? or value == record.send("#{attr_name}_confirmation") + unless record.send("#{attr_name}_confirmation").nil? or value == record.send("#{attr_name}_confirmation") + message = record.errors.generate_message(attr_name, :confirmation, :default => configuration[:message]) + record.errors.add(attr_name, message) + end end - end + end # Encapsulates the pattern of wanting to validate the acceptance of a terms of service check box (or similar agreement). Example: # @@ -422,7 +435,7 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_acceptance_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true, :accept => "1" } + configuration = { :on => :save, :allow_nil => true, :accept => "1" } configuration.update(attr_names.extract_options!) db_cols = begin @@ -434,7 +447,10 @@ module ActiveRecord attr_accessor(*names) validates_each(attr_names,configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message]) unless value == configuration[:accept] + unless value == configuration[:accept] + message = record.errors.generate_message(attr_name, :accepted, :default => configuration[:message]) + record.errors.add(attr_name, message) + end end end @@ -461,7 +477,7 @@ module ActiveRecord # method, proc or string should return or evaluate to a true or false value. # def validates_presence_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:blank], :on => :save } + configuration = { :on => :save } configuration.update(attr_names.extract_options!) # can't use validates_each here, because it cannot cope with nonexistent attributes, @@ -505,11 +521,7 @@ module ActiveRecord # method, proc or string should return or evaluate to a true or false value. def validates_length_of(*attrs) # Merge given options with defaults. - options = { - :too_long => ActiveRecord::Errors.default_error_messages[:too_long], - :too_short => ActiveRecord::Errors.default_error_messages[:too_short], - :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length] - }.merge(DEFAULT_VALIDATION_OPTIONS) + options = {}.merge(DEFAULT_VALIDATION_OPTIONS) options.update(attrs.extract_options!.symbolize_keys) # Ensure that one and only one range option is specified. @@ -531,15 +543,14 @@ module ActiveRecord when :within, :in raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) - too_short = options[:too_short] % option_value.begin - too_long = options[:too_long] % option_value.end - validates_each(attrs, options) do |record, attr, value| value = value.split(//) if value.kind_of?(String) if value.nil? or value.size < option_value.begin - record.errors.add(attr, too_short) + message = record.errors.generate_message(attr, :too_short, :default => options[:too_short], :count => option_value.begin) + record.errors.add(attr, message) elsif value.size > option_value.end - record.errors.add(attr, too_long) + message = record.errors.generate_message(attr, :too_long, :default => options[:too_long], :count => option_value.end) + record.errors.add(attr, message) end end when :is, :minimum, :maximum @@ -549,11 +560,14 @@ module ActiveRecord validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" } message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } - message = (options[:message] || options[message_options[option]]) % option_value - validates_each(attrs, options) do |record, attr, value| value = value.split(//) if value.kind_of?(String) - record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] + unless !value.nil? and value.size.method(validity_checks[option])[option_value] + key = message_options[option] + custom_message = options[:message] || options[key] + message = record.errors.generate_message(attr, key, :default => custom_message, :count => option_value) + record.errors.add(attr, message) + end end end end @@ -595,7 +609,7 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_uniqueness_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken], :case_sensitive => true } + configuration = { :case_sensitive => true } configuration.update(attr_names.extract_options!) validates_each(attr_names,configuration) do |record, attr_name, value| @@ -654,8 +668,11 @@ module ActiveRecord if configuration[:case_sensitive] && finder_class.columns_hash[attr_name.to_s].text? found = results.any? { |a| a[attr_name.to_s] == value } end - - record.errors.add(attr_name, configuration[:message]) if found + + if found + message = record.errors.generate_message(attr_name, :taken, :default => configuration[:message]) + record.errors.add(attr_name, message) + end end end end @@ -685,13 +702,16 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_format_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil } + configuration = { :on => :save, :with => nil } configuration.update(attr_names.extract_options!) raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp) validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message] % value) unless value.to_s =~ configuration[:with] + unless value.to_s =~ configuration[:with] + message = record.errors.generate_message(attr_name, :invalid, :default => configuration[:message], :value => value) + record.errors.add(attr_name, message) + end end end @@ -715,7 +735,7 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_inclusion_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save } + configuration = { :on => :save, :with => nil } configuration.update(attr_names.extract_options!) enum = configuration[:in] || configuration[:within] @@ -723,7 +743,10 @@ module ActiveRecord raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message] % value) unless enum.include?(value) + unless enum.include?(value) + message = record.errors.generate_message(attr_name, :inclusion, :default => configuration[:message], :value => value) + record.errors.add(attr_name, message) + end end end @@ -747,7 +770,7 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_exclusion_of(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:exclusion], :on => :save } + configuration = { :on => :save, :with => nil } configuration.update(attr_names.extract_options!) enum = configuration[:in] || configuration[:within] @@ -755,7 +778,10 @@ module ActiveRecord raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?") validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message] % value) if enum.include?(value) + if enum.include?(value) + message = record.errors.generate_message(attr_name, :exclusion, :default => configuration[:message], :value => value) + record.errors.add(attr_name, message) + end end end @@ -791,12 +817,14 @@ module ActiveRecord # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The # method, proc or string should return or evaluate to a true or false value. def validates_associated(*attr_names) - configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save } + configuration = { :on => :save } configuration.update(attr_names.extract_options!) validates_each(attr_names, configuration) do |record, attr_name, value| - record.errors.add(attr_name, configuration[:message]) unless - (value.is_a?(Array) ? value : [value]).inject(true) { |v, r| (r.nil? || r.valid?) && v } + unless (value.is_a?(Array) ? value : [value]).inject(true) { |v, r| (r.nil? || r.valid?) && v } + message = record.errors.generate_message(attr_name, :invalid, :default => configuration[:message], :value => value) + record.errors.add(attr_name, message) + end end end @@ -844,7 +872,8 @@ module ActiveRecord if configuration[:only_integer] unless raw_value.to_s =~ /\A[+-]?\d+\Z/ - record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number]) + message = record.errors.generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message]) + record.errors.add(attr_name, message) next end raw_value = raw_value.to_i @@ -852,7 +881,8 @@ module ActiveRecord begin raw_value = Kernel.Float(raw_value.to_s) rescue ArgumentError, TypeError - record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number]) + message = record.errors.generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message]) + record.errors.add(attr_name, message) next end end @@ -860,10 +890,12 @@ module ActiveRecord numericality_options.each do |option| case option when :odd, :even - record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[option]) unless raw_value.to_i.method(ALL_NUMERICALITY_CHECKS[option])[] + unless raw_value.to_i.method(ALL_NUMERICALITY_CHECKS[option])[] + message = record.errors.generate_message(attr_name, option, :value => raw_value, :default => configuration[:message]) + record.errors.add(attr_name, message) + end else - message = configuration[:message] || ActiveRecord::Errors.default_error_messages[option] - message = message % configuration[option] if configuration[option] + message = record.errors.generate_message(attr_name, option, :default => configuration[:message], :value => raw_value, :count => configuration[option]) record.errors.add(attr_name, message) unless raw_value.method(ALL_NUMERICALITY_CHECKS[option])[configuration[option]] end end diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb new file mode 100644 index 0000000000..eb454fca20 --- /dev/null +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -0,0 +1,539 @@ +require "cases/helper" +require 'models/topic' +require 'models/reply' + +class ActiveRecordValidationsI18nTests < Test::Unit::TestCase + def setup + reset_callbacks Topic + @topic = Topic.new + I18n.backend.add_translations('en-US', :active_record => {:error_messages => {:custom => nil}}) + end + + def teardown + reset_callbacks Topic + load 'active_record/lang/en-US.rb' + end + + def unique_topic + @unique ||= Topic.create :title => 'unique!' + end + + def replied_topic + @replied_topic ||= begin + topic = Topic.create(:title => "topic") + topic.replies << Reply.new + topic + end + end + + def reset_callbacks(*models) + models.each do |model| + model.instance_variable_set("@validate_callbacks", ActiveSupport::Callbacks::CallbackChain.new) + model.instance_variable_set("@validate_on_create_callbacks", ActiveSupport::Callbacks::CallbackChain.new) + model.instance_variable_set("@validate_on_update_callbacks", ActiveSupport::Callbacks::CallbackChain.new) + end + end + + # ActiveRecord::Errors + + def test_errors_generate_message_translates_custom_model_attribute_key + global_scope = [:active_record, :error_messages] + custom_scope = global_scope + [:custom, 'topic', :title] + + I18n.expects(:translate).with(:invalid, :scope => custom_scope).returns 'translation' + I18n.expects(:translate).with(:invalid, :scope => global_scope).never + + @topic.errors.generate_message :title, :invalid + end + + def test_errors_generate_message_given_a_custom_message_translates_custom_model_attribute_key_with_custom_message_as_default + custom_scope = [:active_record, :error_messages, :custom, 'topic', :title] + + I18n.expects(:translate).with(:invalid, :scope => custom_scope, :default => 'default from class def').returns 'translation' + @topic.errors.generate_message :title, :invalid, :default => 'default from class def' + end + + def test_errors_generate_message_given_no_custom_message_falls_back_to_global_default_key_translation + global_scope = [:active_record, :error_messages] + custom_scope = global_scope + [:custom, 'topic', :title] + + I18n.stubs(:translate).with(:invalid, :scope => custom_scope).returns nil + I18n.expects(:translate).with(:invalid, :scope => global_scope) + @topic.errors.generate_message :title, :invalid + end + + def test_errors_add_given_no_message_it_translates_invalid + I18n.expects(:translate).with(:"active_record.error_messages.invalid") + @topic.errors.add :title + end + + def test_errors_add_on_empty_generates_message + @topic.errors.expects(:generate_message).with(:title, :empty, {:default => nil}) + @topic.errors.add_on_empty :title + end + + def test_errors_add_on_empty_generates_message_with_custom_default_message + @topic.errors.expects(:generate_message).with(:title, :empty, {:default => 'custom'}) + @topic.errors.add_on_empty :title, 'custom' + end + + def test_errors_add_on_blank_generates_message + @topic.errors.expects(:generate_message).with(:title, :blank, {:default => nil}) + @topic.errors.add_on_blank :title + end + + def test_errors_add_on_blank_generates_message_with_custom_default_message + @topic.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'}) + @topic.errors.add_on_blank :title, 'custom' + end + + def test_errors_full_messages_translates_human_attribute_name_for_model_attributes + @topic.errors.instance_variable_set :@errors, { 'title' => 'empty' } + I18n.expects(:translate).with(:"active_record.human_attribute_names.topic.title", 'en-US').returns('Title') + @topic.errors.full_messages :locale => 'en-US' + end + + + # ActiveRecord::Validations + + # validates_confirmation_of + + def test_validates_confirmation_of_generates_message + Topic.validates_confirmation_of :title + @topic.title_confirmation = 'foo' + @topic.errors.expects(:generate_message).with(:title, :confirmation, {:default => nil}) + @topic.valid? + end + + def test_validates_confirmation_of_generates_message_with_custom_default_message + Topic.validates_confirmation_of :title, :message => 'custom' + @topic.title_confirmation = 'foo' + @topic.errors.expects(:generate_message).with(:title, :confirmation, {:default => 'custom'}) + @topic.valid? + end + + def test_validates_confirmation_of_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:confirmation => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} + + Topic.validates_confirmation_of :title + @topic.title_confirmation = 'foo' + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_confirmation_of_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} + + Topic.validates_confirmation_of :title + @topic.title_confirmation = 'foo' + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_acceptance_of + + def test_validates_acceptance_of_generates_message + Topic.validates_acceptance_of :title, :allow_nil => false + @topic.errors.expects(:generate_message).with(:title, :accepted, {:default => nil}) + @topic.valid? + end + + def test_validates_acceptance_of_generates_message_with_custom_default_message + Topic.validates_acceptance_of :title, :message => 'custom', :allow_nil => false + @topic.errors.expects(:generate_message).with(:title, :accepted, {:default => 'custom'}) + @topic.valid? + end + + def test_validates_acceptance_of_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:accepted => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:accepted => 'global message'}} + + Topic.validates_acceptance_of :title, :allow_nil => false + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_acceptance_of_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:accepted => 'global message'}} + + Topic.validates_acceptance_of :title, :allow_nil => false + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_presence_of + + def test_validates_presence_of_generates_message + Topic.validates_presence_of :title + @topic.errors.expects(:generate_message).with(:title, :blank, {:default => nil}) + @topic.valid? + end + + def test_validates_presence_of_generates_message_with_custom_default_message + Topic.validates_presence_of :title, :message => 'custom' + @topic.errors.expects(:generate_message).with(:title, :blank, {:default => 'custom'}) + @topic.valid? + end + + def test_validates_presence_of_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:blank => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} + + Topic.validates_presence_of :title + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_presence_of_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} + + Topic.validates_presence_of :title + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_length_of :within + + def test_validates_length_of_within_generates_message + Topic.validates_length_of :title, :within => 3..5 + @topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => nil}) + @topic.valid? + end + + def test_validates_length_of_within_generates_message_with_custom_default_message + Topic.validates_length_of :title, :within => 3..5, :too_short => 'custom' + @topic.errors.expects(:generate_message).with(:title, :too_short, {:count => 3, :default => 'custom'}) + @topic.valid? + end + + def test_validates_length_of_within_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:too_short => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:too_short => 'global message'}} + + Topic.validates_length_of :title, :within => 3..5 + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_length_of_within_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:too_short => 'global message'}} + + Topic.validates_length_of :title, :within => 3..5 + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_length_of :is + + def test_validates_length_of_is_generates_message + Topic.validates_length_of :title, :is => 5 + @topic.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => nil}) + @topic.valid? + end + + def test_validates_length_of_is_generates_message_with_custom_default_message + Topic.validates_length_of :title, :is => 5, :message => 'custom' + @topic.errors.expects(:generate_message).with(:title, :wrong_length, {:count => 5, :default => 'custom'}) + @topic.valid? + end + + def test_validates_length_of_within_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} + + Topic.validates_length_of :title, :is => 5 + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_length_of_within_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} + + Topic.validates_length_of :title, :is => 5 + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_uniqueness_of + + def test_validates_uniqueness_of_generates_message + Topic.validates_uniqueness_of :title + @topic.title = unique_topic.title + @topic.errors.expects(:generate_message).with(:title, :taken, {:default => nil}) + @topic.valid? + end + + def test_validates_uniqueness_of_generates_message_with_custom_default_message + Topic.validates_uniqueness_of :title, :message => 'custom' + @topic.title = unique_topic.title + @topic.errors.expects(:generate_message).with(:title, :taken, {:default => 'custom'}) + @topic.valid? + end + + def test_validates_length_of_within_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} + + Topic.validates_length_of :title, :is => 5 + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_length_of_within_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} + + Topic.validates_length_of :title, :is => 5 + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_format_of + + def test_validates_format_of_generates_message + Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/ + @topic.title = '72x' + @topic.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => nil}) + @topic.valid? + end + + def test_validates_format_of_generates_message_with_custom_default_message + Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/, :message => 'custom' + @topic.title = '72x' + @topic.errors.expects(:generate_message).with(:title, :invalid, {:value => '72x', :default => 'custom'}) + @topic.valid? + end + + def test_validates_format_of_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:invalid => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + + Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/ + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_format_of_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + + Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/ + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_inclusion_of + + def test_validates_inclusion_of_generates_message + Topic.validates_inclusion_of :title, :in => %w(a b c) + @topic.title = 'z' + @topic.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => nil}) + @topic.valid? + end + + def test_validates_inclusion_of_generates_message_with_custom_default_message + Topic.validates_inclusion_of :title, :in => %w(a b c), :message => 'custom' + @topic.title = 'z' + @topic.errors.expects(:generate_message).with(:title, :inclusion, {:value => 'z', :default => 'custom'}) + @topic.valid? + end + + def test_validates_inclusion_of_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:inclusion => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:inclusion => 'global message'}} + + Topic.validates_inclusion_of :title, :in => %w(a b c) + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_inclusion_of_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:inclusion => 'global message'}} + + Topic.validates_inclusion_of :title, :in => %w(a b c) + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_exclusion_of + + def test_validates_exclusion_of_generates_message + Topic.validates_exclusion_of :title, :in => %w(a b c) + @topic.title = 'a' + @topic.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => nil}) + @topic.valid? + end + + def test_validates_exclusion_of_generates_message_with_custom_default_message + Topic.validates_exclusion_of :title, :in => %w(a b c), :message => 'custom' + @topic.title = 'a' + @topic.errors.expects(:generate_message).with(:title, :exclusion, {:value => 'a', :default => 'custom'}) + @topic.valid? + end + + def test_validates_exclusion_of_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:exclusion => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:exclusion => 'global message'}} + + Topic.validates_exclusion_of :title, :in => %w(a b c) + @topic.title = 'a' + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_exclusion_of_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:exclusion => 'global message'}} + + Topic.validates_exclusion_of :title, :in => %w(a b c) + @topic.title = 'a' + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_numericality_of :only_integer + + def test_validates_numericality_of_only_integer_generates_message + Topic.validates_numericality_of :title, :only_integer => true + @topic.title = 'a' + @topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => nil}) + @topic.valid? + end + + def test_validates_numericality_of_only_integer_generates_message_with_custom_default_message + Topic.validates_numericality_of :title, :only_integer => true, :message => 'custom' + @topic.title = 'a' + @topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'}) + @topic.valid? + end + + def test_validates_numericality_of_only_integer_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:not_a_number => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:not_a_number => 'global message'}} + + Topic.validates_numericality_of :title, :only_integer => true + @topic.title = 'a' + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_numericality_of_only_integer_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:not_a_number => 'global message'}} + + Topic.validates_numericality_of :title, :only_integer => true + @topic.title = 'a' + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_numericality_of :odd + + def test_validates_numericality_of_odd_generates_message + Topic.validates_numericality_of :title, :only_integer => true, :odd => true + @topic.title = 0 + @topic.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => nil}) + @topic.valid? + end + + def test_validates_numericality_of_odd_generates_message_with_custom_default_message + Topic.validates_numericality_of :title, :only_integer => true, :odd => true, :message => 'custom' + @topic.title = 0 + @topic.errors.expects(:generate_message).with(:title, :odd, {:value => 0, :default => 'custom'}) + @topic.valid? + end + + def test_validates_numericality_of_odd_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:odd => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:odd => 'global message'}} + + Topic.validates_numericality_of :title, :only_integer => true, :odd => true + @topic.title = 0 + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_numericality_of_odd_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:odd => 'global message'}} + + Topic.validates_numericality_of :title, :only_integer => true, :odd => true + @topic.title = 0 + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_numericality_of :less_than + + def test_validates_numericality_of_less_than_generates_message + Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0 + @topic.title = 1 + @topic.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => nil}) + @topic.valid? + end + + def test_validates_numericality_of_odd_generates_message_with_custom_default_message + Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0, :message => 'custom' + @topic.title = 1 + @topic.errors.expects(:generate_message).with(:title, :less_than, {:value => 1, :count => 0, :default => 'custom'}) + @topic.valid? + end + + def test_validates_numericality_of_less_than_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:less_than => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:less_than => 'global message'}} + + Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0 + @topic.title = 1 + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_numericality_of_less_than_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:less_than => 'global message'}} + + Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0 + @topic.title = 1 + @topic.valid? + assert_equal 'global message', @topic.errors.on(:title) + end + + + # validates_associated + + def test_validates_associated_generates_message + Topic.validates_associated :replies + replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil}) + replied_topic.valid? + end + + def test_validates_associated_generates_message_with_custom_default_message + Topic.validates_associated :replies + replied_topic.errors.expects(:generate_message).with(:replies, :invalid, {:value => replied_topic.replies, :default => nil}) + replied_topic.valid? + end + + def test_validates_associated_finds_custom_model_key_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:replies => {:invalid => 'custom message'}}}}} + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + + Topic.validates_associated :replies + replied_topic.valid? + assert_equal 'custom message', replied_topic.errors.on(:replies) + end + + def test_validates_associated_finds_global_default_translation + I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + + Topic.validates_associated :replies + replied_topic.valid? + assert_equal 'global message', replied_topic.errors.on(:replies) + end +end \ No newline at end of file -- cgit v1.2.3