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 From 2fe4d350e98d7f825cf3d1f9233075a5a79e32a1 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Thu, 19 Jun 2008 18:31:11 +0200 Subject: make ActiveRecord::Errors.default_error_messages look up translated error messages --- activerecord/lib/active_record/validations.rb | 33 ++++++--------------------- 1 file changed, 7 insertions(+), 26 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index f54fb80137..0ca68989d2 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -18,37 +18,18 @@ module ActiveRecord # determine whether the object is in a valid state to be saved. See usage example in Validations. class Errors include Enumerable + + class << self + def default_error_messages + # TODO deprecate this? + :'active_record.error_messages'.t + end + end def initialize(base) # :nodoc: @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 - - # Adds an error to the base object instead of any particular attribute. This is used # to report errors that don't tie to any specific attribute, but rather to the object # as a whole. These error messages don't get prepended with any field name when iterating -- cgit v1.2.3 From 585c8c17c303fc46fcf014a644a541eae6cb5ffd Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Fri, 20 Jun 2008 09:13:20 +0200 Subject: rename Backend::Simple#add_translations to set_translations because it overwrites existing translations --- activerecord/lib/active_record/lang/en-US.rb | 2 +- activerecord/lib/active_record/validations.rb | 2 +- activerecord/test/cases/validations_i18n_test.rb | 80 ++++++++++++------------ 3 files changed, 42 insertions(+), 42 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/lang/en-US.rb b/activerecord/lib/active_record/lang/en-US.rb index 7c3bcfd85e..f307f40f1a 100644 --- a/activerecord/lib/active_record/lang/en-US.rb +++ b/activerecord/lib/active_record/lang/en-US.rb @@ -1,4 +1,4 @@ -I18n.backend.add_translations :'en-US', { +I18n.backend.set_translations :'en-US', { :active_record => { :error_messages => { :inclusion => "is not included in the list", diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 0ca68989d2..bcb204f1ba 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -21,7 +21,7 @@ module ActiveRecord class << self def default_error_messages - # TODO deprecate this? + # ActiveSupport::Deprecation.warn("ActiveRecord::Errors.default_error_messages has been deprecated. Please use :'active_record.error_messages'.t.") :'active_record.error_messages'.t end end diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index eb454fca20..8f8574c242 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -6,7 +6,7 @@ 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}}) + I18n.backend.set_translations('en-US', :active_record => {:error_messages => {:custom => nil}}) end def teardown @@ -113,8 +113,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:confirmation => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} Topic.validates_confirmation_of :title @topic.title_confirmation = 'foo' @@ -123,7 +123,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_confirmation_of_finds_global_default_translation - I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} Topic.validates_confirmation_of :title @topic.title_confirmation = 'foo' @@ -147,8 +147,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:accepted => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:accepted => 'global message'}} Topic.validates_acceptance_of :title, :allow_nil => false @topic.valid? @@ -156,7 +156,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_acceptance_of_finds_global_default_translation - I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:accepted => 'global message'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:accepted => 'global message'}} Topic.validates_acceptance_of :title, :allow_nil => false @topic.valid? @@ -179,8 +179,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:blank => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} Topic.validates_presence_of :title @topic.valid? @@ -188,7 +188,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_presence_of_finds_global_default_translation - I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} Topic.validates_presence_of :title @topic.valid? @@ -211,8 +211,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:too_short => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:too_short => 'global message'}} Topic.validates_length_of :title, :within => 3..5 @topic.valid? @@ -220,7 +220,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:too_short => 'global message'}} Topic.validates_length_of :title, :within => 3..5 @topic.valid? @@ -243,8 +243,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} Topic.validates_length_of :title, :is => 5 @topic.valid? @@ -252,7 +252,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} Topic.validates_length_of :title, :is => 5 @topic.valid? @@ -277,8 +277,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} Topic.validates_length_of :title, :is => 5 @topic.valid? @@ -286,7 +286,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} Topic.validates_length_of :title, :is => 5 @topic.valid? @@ -311,8 +311,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:invalid => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/ @topic.valid? @@ -320,7 +320,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_format_of_finds_global_default_translation - I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/ @topic.valid? @@ -345,8 +345,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:inclusion => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:inclusion => 'global message'}} Topic.validates_inclusion_of :title, :in => %w(a b c) @topic.valid? @@ -354,7 +354,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_inclusion_of_finds_global_default_translation - I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:inclusion => 'global message'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:inclusion => 'global message'}} Topic.validates_inclusion_of :title, :in => %w(a b c) @topic.valid? @@ -379,8 +379,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:exclusion => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:exclusion => 'global message'}} Topic.validates_exclusion_of :title, :in => %w(a b c) @topic.title = 'a' @@ -389,7 +389,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_exclusion_of_finds_global_default_translation - I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:exclusion => 'global message'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:exclusion => 'global message'}} Topic.validates_exclusion_of :title, :in => %w(a b c) @topic.title = 'a' @@ -415,8 +415,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:not_a_number => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:not_a_number => 'global message'}} Topic.validates_numericality_of :title, :only_integer => true @topic.title = 'a' @@ -425,7 +425,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:not_a_number => 'global message'}} Topic.validates_numericality_of :title, :only_integer => true @topic.title = 'a' @@ -451,8 +451,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:odd => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:odd => 'global message'}} Topic.validates_numericality_of :title, :only_integer => true, :odd => true @topic.title = 0 @@ -461,7 +461,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_numericality_of_odd_finds_global_default_translation - I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:odd => 'global message'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:odd => 'global message'}} Topic.validates_numericality_of :title, :only_integer => true, :odd => true @topic.title = 0 @@ -487,8 +487,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:less_than => 'custom message'}}}}} + I18n.backend.set_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 @@ -497,7 +497,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_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 @@ -521,8 +521,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:replies => {:invalid => 'custom message'}}}}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} Topic.validates_associated :replies replied_topic.valid? @@ -530,7 +530,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_associated_finds_global_default_translation - I18n.backend.add_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} Topic.validates_associated :replies replied_topic.valid? -- cgit v1.2.3 From c1e2506494107892a0962b8491cd234f77949c08 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sat, 21 Jun 2008 11:27:19 +0200 Subject: Changed process of storing translations from the client libraries to the backend: clients now can pass a block to backend#populate which can contain code to load and register translations. This makes sense for backends that persist their translations (e.g. to db) so the repeated loading and passing of translations throughout the server startup would be wasted resources. --- activerecord/lib/active_record.rb | 5 +- activerecord/lib/active_record/lang/en-US.rb | 2 +- activerecord/test/cases/validations_i18n_test.rb | 80 ++++++++++++------------ 3 files changed, 45 insertions(+), 42 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index b379bd26f8..71882833d4 100755 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -81,4 +81,7 @@ require 'active_record/connection_adapters/abstract_adapter' require 'active_record/schema_dumper' -require 'active_record/lang/en-US.rb' +I18n.backend.populate do + require 'active_record/lang/en-US.rb' +end + diff --git a/activerecord/lib/active_record/lang/en-US.rb b/activerecord/lib/active_record/lang/en-US.rb index f307f40f1a..b31e13ed3a 100644 --- a/activerecord/lib/active_record/lang/en-US.rb +++ b/activerecord/lib/active_record/lang/en-US.rb @@ -1,4 +1,4 @@ -I18n.backend.set_translations :'en-US', { +I18n.backend.store_translations :'en-US', { :active_record => { :error_messages => { :inclusion => "is not included in the list", diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index 8f8574c242..de844bf5a6 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -6,7 +6,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def setup reset_callbacks Topic @topic = Topic.new - I18n.backend.set_translations('en-US', :active_record => {:error_messages => {:custom => nil}}) + I18n.backend.store_translations('en-US', :active_record => {:error_messages => {:custom => nil}}) end def teardown @@ -113,8 +113,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_confirmation_of_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:confirmation => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:confirmation => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} Topic.validates_confirmation_of :title @topic.title_confirmation = 'foo' @@ -123,7 +123,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_confirmation_of_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} Topic.validates_confirmation_of :title @topic.title_confirmation = 'foo' @@ -147,8 +147,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_acceptance_of_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:accepted => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:accepted => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:accepted => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:accepted => 'global message'}} Topic.validates_acceptance_of :title, :allow_nil => false @topic.valid? @@ -156,7 +156,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_acceptance_of_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:accepted => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:accepted => 'global message'}} Topic.validates_acceptance_of :title, :allow_nil => false @topic.valid? @@ -179,8 +179,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_presence_of_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:blank => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:blank => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} Topic.validates_presence_of :title @topic.valid? @@ -188,7 +188,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_presence_of_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} Topic.validates_presence_of :title @topic.valid? @@ -211,8 +211,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_length_of_within_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:too_short => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:too_short => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:too_short => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:too_short => 'global message'}} Topic.validates_length_of :title, :within => 3..5 @topic.valid? @@ -220,7 +220,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_length_of_within_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:too_short => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:too_short => 'global message'}} Topic.validates_length_of :title, :within => 3..5 @topic.valid? @@ -243,8 +243,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_length_of_within_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} Topic.validates_length_of :title, :is => 5 @topic.valid? @@ -252,7 +252,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_length_of_within_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} Topic.validates_length_of :title, :is => 5 @topic.valid? @@ -277,8 +277,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_length_of_within_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} Topic.validates_length_of :title, :is => 5 @topic.valid? @@ -286,7 +286,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_length_of_within_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:wrong_length => 'global message'}} Topic.validates_length_of :title, :is => 5 @topic.valid? @@ -311,8 +311,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_format_of_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:invalid => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:invalid => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/ @topic.valid? @@ -320,7 +320,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_format_of_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/ @topic.valid? @@ -345,8 +345,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_inclusion_of_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:inclusion => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:inclusion => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:inclusion => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:inclusion => 'global message'}} Topic.validates_inclusion_of :title, :in => %w(a b c) @topic.valid? @@ -354,7 +354,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_inclusion_of_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:inclusion => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:inclusion => 'global message'}} Topic.validates_inclusion_of :title, :in => %w(a b c) @topic.valid? @@ -379,8 +379,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_exclusion_of_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:exclusion => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:exclusion => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:exclusion => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:exclusion => 'global message'}} Topic.validates_exclusion_of :title, :in => %w(a b c) @topic.title = 'a' @@ -389,7 +389,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_exclusion_of_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:exclusion => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:exclusion => 'global message'}} Topic.validates_exclusion_of :title, :in => %w(a b c) @topic.title = 'a' @@ -415,8 +415,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_numericality_of_only_integer_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:not_a_number => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:not_a_number => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:not_a_number => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:not_a_number => 'global message'}} Topic.validates_numericality_of :title, :only_integer => true @topic.title = 'a' @@ -425,7 +425,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_numericality_of_only_integer_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:not_a_number => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:not_a_number => 'global message'}} Topic.validates_numericality_of :title, :only_integer => true @topic.title = 'a' @@ -451,8 +451,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_numericality_of_odd_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:odd => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:odd => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:odd => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:odd => 'global message'}} Topic.validates_numericality_of :title, :only_integer => true, :odd => true @topic.title = 0 @@ -461,7 +461,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_numericality_of_odd_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:odd => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:odd => 'global message'}} Topic.validates_numericality_of :title, :only_integer => true, :odd => true @topic.title = 0 @@ -487,8 +487,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_numericality_of_less_than_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:less_than => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:less_than => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:less_than => 'custom message'}}}}} + I18n.backend.store_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 @@ -497,7 +497,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_numericality_of_less_than_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:less_than => 'global message'}} + I18n.backend.store_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 @@ -521,8 +521,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_associated_finds_custom_model_key_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:replies => {:invalid => 'custom message'}}}}} - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:replies => {:invalid => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} Topic.validates_associated :replies replied_topic.valid? @@ -530,7 +530,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end def test_validates_associated_finds_global_default_translation - I18n.backend.set_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:invalid => 'global message'}} Topic.validates_associated :replies replied_topic.valid? -- cgit v1.2.3 From 428aa24d24032d382dc3d9ccf131e0c874043dbd Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sat, 21 Jun 2008 11:35:02 +0200 Subject: Renamed lang/ to locale/ because that's what we seem to standarize on. Also, in future this place can be used for data/code that's not literally translations but conceptually belongs to the locale (like custom pluralization algorithms etc.). --- activerecord/lib/active_record.rb | 2 +- activerecord/lib/active_record/lang/en-US.rb | 25 ------------------------ activerecord/lib/active_record/locale/en-US.rb | 25 ++++++++++++++++++++++++ activerecord/test/cases/validations_i18n_test.rb | 2 +- 4 files changed, 27 insertions(+), 27 deletions(-) delete mode 100644 activerecord/lib/active_record/lang/en-US.rb create mode 100644 activerecord/lib/active_record/locale/en-US.rb (limited to 'activerecord') diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 71882833d4..17a7949959 100755 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -82,6 +82,6 @@ require 'active_record/connection_adapters/abstract_adapter' require 'active_record/schema_dumper' I18n.backend.populate do - require 'active_record/lang/en-US.rb' + require 'active_record/locale/en-US.rb' end diff --git a/activerecord/lib/active_record/lang/en-US.rb b/activerecord/lib/active_record/lang/en-US.rb deleted file mode 100644 index b31e13ed3a..0000000000 --- a/activerecord/lib/active_record/lang/en-US.rb +++ /dev/null @@ -1,25 +0,0 @@ -I18n.backend.store_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/locale/en-US.rb b/activerecord/lib/active_record/locale/en-US.rb new file mode 100644 index 0000000000..b31e13ed3a --- /dev/null +++ b/activerecord/lib/active_record/locale/en-US.rb @@ -0,0 +1,25 @@ +I18n.backend.store_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/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index de844bf5a6..10e36b1512 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -11,7 +11,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def teardown reset_callbacks Topic - load 'active_record/lang/en-US.rb' + load 'active_record/locale/en-US.rb' end def unique_topic -- cgit v1.2.3 From 8bfdabbd8b5137f91d8bcddc8c3d18961c8e316b Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sat, 21 Jun 2008 17:50:37 +0200 Subject: incorporate #translate usage with several default keys (use first default key that resolves to a translation). this might, depending on the backend implementation save some expensive lookups (like db lookups) --- activerecord/lib/active_record/validations.rb | 19 +++++- activerecord/test/cases/validations_i18n_test.rb | 86 ++++++++++-------------- 2 files changed, 51 insertions(+), 54 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index bcb204f1ba..49d3c59ca7 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -66,9 +66,11 @@ module ActiveRecord 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)) + msgs = base_classes(@base.class).map{|klass| :"custom.#{klass.name.underscore}.#{attr}.#{key}"} + msgs << options[:default] if options[:default] + msgs << key + + I18n.t options.merge(:default => msgs, :scope => [:active_record, :error_messages]) end # Returns true if the specified +attribute+ has errors associated with it. @@ -217,6 +219,17 @@ module ActiveRecord full_messages.each { |msg| e.error(msg) } end end + + protected + + # TODO maybe this should be on ActiveRecord::Base, maybe #self_and_descendents_from_active_record + def base_classes(klass) + classes = [klass] + while klass != klass.base_class + classes << klass = klass.superclass + end + classes + end end diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index 10e36b1512..37a7c1ce49 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -40,31 +40,15 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + I18n.expects(:t).with :scope => [:active_record, :error_messages], :default => [:"custom.topic.title.invalid", 'default from class def', :invalid] + @topic.errors.generate_message :title, :invalid, :default => 'default from class def' end - def test_errors_generate_message_given_a_custom_message_translates_custom_model_attribute_key_with_custom_message_as_default + def test_errors_generate_message_translates_custom_model_attribute_keys_with_sti 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 + I18n.expects(:t).with :scope => [:active_record, :error_messages], :default => [:"custom.reply.title.invalid", :"custom.topic.title.invalid", 'default from class def', :invalid] + Reply.new.errors.generate_message :title, :invalid, :default => 'default from class def' end def test_errors_add_on_empty_generates_message @@ -115,7 +99,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_confirmation_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:confirmation => 'custom message'}}}}} I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} - + Topic.validates_confirmation_of :title @topic.title_confirmation = 'foo' @topic.valid? @@ -124,7 +108,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_confirmation_of_finds_global_default_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:confirmation => 'global message'}} - + Topic.validates_confirmation_of :title @topic.title_confirmation = 'foo' @topic.valid? @@ -133,13 +117,13 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase # 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'}) @@ -149,7 +133,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_acceptance_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:accepted => 'custom message'}}}}} I18n.backend.store_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) @@ -157,7 +141,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_acceptance_of_finds_global_default_translation I18n.backend.store_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) @@ -165,7 +149,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase # 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}) @@ -181,7 +165,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_presence_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:blank => 'custom message'}}}}} I18n.backend.store_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) @@ -189,7 +173,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_presence_of_finds_global_default_translation I18n.backend.store_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) @@ -197,7 +181,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase # 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}) @@ -213,7 +197,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_length_of_within_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:too_short => 'custom message'}}}}} I18n.backend.store_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) @@ -221,7 +205,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_length_of_within_finds_global_default_translation I18n.backend.store_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) @@ -245,7 +229,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_length_of_within_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} I18n.backend.store_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) @@ -253,7 +237,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_length_of_within_finds_global_default_translation I18n.backend.store_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) @@ -279,7 +263,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_length_of_within_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} I18n.backend.store_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) @@ -287,7 +271,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_length_of_within_finds_global_default_translation I18n.backend.store_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) @@ -313,7 +297,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_format_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:invalid => 'custom message'}}}}} I18n.backend.store_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) @@ -321,7 +305,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_format_of_finds_global_default_translation I18n.backend.store_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) @@ -347,7 +331,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_inclusion_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:inclusion => 'custom message'}}}}} I18n.backend.store_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) @@ -355,7 +339,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_inclusion_of_finds_global_default_translation I18n.backend.store_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) @@ -381,7 +365,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_exclusion_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:exclusion => 'custom message'}}}}} I18n.backend.store_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? @@ -390,7 +374,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_exclusion_of_finds_global_default_translation I18n.backend.store_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? @@ -417,7 +401,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_numericality_of_only_integer_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:not_a_number => 'custom message'}}}}} I18n.backend.store_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? @@ -426,7 +410,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_numericality_of_only_integer_finds_global_default_translation I18n.backend.store_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? @@ -453,7 +437,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_numericality_of_odd_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:odd => 'custom message'}}}}} I18n.backend.store_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? @@ -462,7 +446,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_numericality_of_odd_finds_global_default_translation I18n.backend.store_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? @@ -489,7 +473,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_numericality_of_less_than_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:less_than => 'custom message'}}}}} I18n.backend.store_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? @@ -498,7 +482,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_numericality_of_less_than_finds_global_default_translation I18n.backend.store_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? @@ -523,7 +507,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_associated_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:replies => {:invalid => 'custom message'}}}}} I18n.backend.store_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) @@ -531,7 +515,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase def test_validates_associated_finds_global_default_translation I18n.backend.store_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) -- cgit v1.2.3 From 0dddba41fcfcd28de2ce1a88a23514fbde53afcf Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Mon, 23 Jun 2008 14:33:29 +0200 Subject: rather cosmetic improvements of test coverage --- activerecord/lib/active_record/validations.rb | 8 +-- activerecord/test/cases/validations_i18n_test.rb | 62 ++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 7 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 49d3c59ca7..5bbd10394c 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -21,8 +21,8 @@ module ActiveRecord class << self def default_error_messages - # ActiveSupport::Deprecation.warn("ActiveRecord::Errors.default_error_messages has been deprecated. Please use :'active_record.error_messages'.t.") - :'active_record.error_messages'.t + ActiveSupport::Deprecation.warn("ActiveRecord::Errors.default_error_messages has been deprecated. Please use 'active_record.error_messages'.t.") + 'active_record.error_messages'.t end end @@ -163,7 +163,7 @@ module ActiveRecord @errors.each_key do |attr| @errors[attr].each do |message| next unless message - + if attr == "base" full_messages << message else @@ -872,7 +872,7 @@ module ActiveRecord end raw_value = raw_value.to_i else - begin + begin raw_value = Kernel.Float(raw_value.to_s) rescue ArgumentError, TypeError message = record.errors.generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message]) diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index 37a7c1ce49..158ff69e57 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -34,6 +34,12 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end end + def test_default_error_messages_is_deprecated + assert_deprecated('ActiveRecord::Errors.default_error_messages') do + ActiveRecord::Errors.default_error_messages + end + end + # ActiveRecord::Errors def test_errors_generate_message_translates_custom_model_attribute_key @@ -182,18 +188,32 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase # validates_length_of :within - def test_validates_length_of_within_generates_message + def test_validates_length_of_within_generates_message_with_title_too_short 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 + def test_validates_length_of_within_generates_message_with_title_too_short_and_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_generates_message_with_title_too_long + Topic.validates_length_of :title, :within => 3..5 + @topic.title = 'this title is too long' + @topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil}) + @topic.valid? + end + + def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message + Topic.validates_length_of :title, :within => 3..5, :too_long => 'custom' + @topic.title = 'this title is too long' + @topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'}) + @topic.valid? + end + def test_validates_length_of_within_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:too_short => 'custom message'}}}}} I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:too_short => 'global message'}} @@ -382,7 +402,43 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end - # validates_numericality_of :only_integer + # validates_numericality_of without :only_integer + + def test_validates_numericality_of_generates_message + Topic.validates_numericality_of :title + @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_generates_message_with_custom_default_message + Topic.validates_numericality_of :title, :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_finds_custom_model_key_translation + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:not_a_number => 'custom message'}}}}} + I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:not_a_number => 'global message'}} + + Topic.validates_numericality_of :title + @topic.title = 'a' + @topic.valid? + assert_equal 'custom message', @topic.errors.on(:title) + end + + def test_validates_numericality_of_finds_global_default_translation + I18n.backend.store_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 with :only_integer def test_validates_numericality_of_only_integer_generates_message Topic.validates_numericality_of :title, :only_integer => true -- cgit v1.2.3 From 77177441d1bd8f62c5b6a990ddee155061df661c Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Mon, 23 Jun 2008 14:49:47 +0200 Subject: including rcov shell scripts for reference --- activerecord/test/i18n_coverage | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 activerecord/test/i18n_coverage (limited to 'activerecord') diff --git a/activerecord/test/i18n_coverage b/activerecord/test/i18n_coverage new file mode 100755 index 0000000000..1589a6c06f --- /dev/null +++ b/activerecord/test/i18n_coverage @@ -0,0 +1,6 @@ +rcov -I connections/native_mysql \ +-x cases/helper,config,connection,models \ +-i active_record/validations.rb \ +cases/validations_i18n_test.rb \ + +# cases/validations_test.rb \ No newline at end of file -- cgit v1.2.3 From 8461526f346b8d8387ba3b74221fbeefef3aefeb Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Mon, 23 Jun 2008 14:55:07 +0200 Subject: silence deprecation warning during validations test --- activerecord/test/cases/validations_test.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 7b71647d25..ad27ac951c 100755 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -853,7 +853,9 @@ class ValidationsTest < ActiveRecord::TestCase end def test_validates_length_with_globally_modified_error_message - ActiveRecord::Errors.default_error_messages[:too_short] = 'tu est trops petit hombre %d' + ActiveSupport::Deprecation.silence do + ActiveRecord::Errors.default_error_messages[:too_short] = 'tu est trops petit hombre %d' + end Topic.validates_length_of :title, :minimum => 10 t = Topic.create(:title => 'too short') assert !t.valid? -- cgit v1.2.3 From 66c2508ebbca06e551255a76cc47a1608f091992 Mon Sep 17 00:00:00 2001 From: Luca Guidi Date: Fri, 27 Jun 2008 15:00:55 +0200 Subject: Make sure mocha is available --- activerecord/test/cases/validations_i18n_test.rb | 576 ++++++++++++----------- 1 file changed, 310 insertions(+), 266 deletions(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index 158ff69e57..53e90f4d53 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -41,66 +41,307 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase end # ActiveRecord::Errors + uses_mocha 'ActiveRecord::Errors' do + 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(:t).with :scope => [:active_record, :error_messages], :default => [:"custom.topic.title.invalid", 'default from class def', :invalid] + @topic.errors.generate_message :title, :invalid, :default => 'default from class def' + end + + def test_errors_generate_message_translates_custom_model_attribute_keys_with_sti + custom_scope = [:active_record, :error_messages, :custom, 'topic', :title] + + I18n.expects(:t).with :scope => [:active_record, :error_messages], :default => [:"custom.reply.title.invalid", :"custom.topic.title.invalid", 'default from class def', :invalid] + Reply.new.errors.generate_message :title, :invalid, :default => 'default from class def' + 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 + end - def test_errors_generate_message_translates_custom_model_attribute_key - global_scope = [:active_record, :error_messages] - custom_scope = global_scope + [:custom, 'topic', :title] + # ActiveRecord::Validations + uses_mocha 'ActiveRecord::Validations' do + # validates_confirmation_of w/ mocha + + 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 - I18n.expects(:t).with :scope => [:active_record, :error_messages], :default => [:"custom.topic.title.invalid", 'default from class def', :invalid] - @topic.errors.generate_message :title, :invalid, :default => 'default from class def' - end - - def test_errors_generate_message_translates_custom_model_attribute_keys_with_sti - custom_scope = [:active_record, :error_messages, :custom, 'topic', :title] + # validates_acceptance_of w/ mocha + + 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 - I18n.expects(:t).with :scope => [:active_record, :error_messages], :default => [:"custom.reply.title.invalid", :"custom.topic.title.invalid", 'default from class def', :invalid] - Reply.new.errors.generate_message :title, :invalid, :default => 'default from class def' - 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? + # validates_presence_of w/ mocha + + 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_length_of_within_generates_message_with_title_too_short + 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_title_too_short_and_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_generates_message_with_title_too_long + Topic.validates_length_of :title, :within => 3..5 + @topic.title = 'this title is too long' + @topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil}) + @topic.valid? + end + + def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message + Topic.validates_length_of :title, :within => 3..5, :too_long => 'custom' + @topic.title = 'this title is too long' + @topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'}) + @topic.valid? + end + + # validates_length_of :within w/ mocha + + def test_validates_length_of_within_generates_message_with_title_too_short + 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_title_too_short_and_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_generates_message_with_title_too_long + Topic.validates_length_of :title, :within => 3..5 + @topic.title = 'this title is too long' + @topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil}) + @topic.valid? + end + + def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message + Topic.validates_length_of :title, :within => 3..5, :too_long => 'custom' + @topic.title = 'this title is too long' + @topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'}) + @topic.valid? + end + + # validates_length_of :is w/ mocha + + 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 + + # validates_uniqueness_of w/ mocha + + 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 + + # validates_format_of w/ mocha + + 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 + + # validates_inclusion_of w/ mocha + + 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 + + # validates_exclusion_of w/ mocha + + 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 + + # validates_numericality_of without :only_integer w/ mocha + + def test_validates_numericality_of_generates_message + Topic.validates_numericality_of :title + @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_generates_message_with_custom_default_message + Topic.validates_numericality_of :title, :message => 'custom' + @topic.title = 'a' + @topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'}) + @topic.valid? + end + + # validates_numericality_of with :only_integer w/ mocha + + 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 + + # validates_numericality_of :odd w/ mocha + + 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 + + # validates_numericality_of :less_than w/ mocha + + 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 + + # validates_associated w/ mocha + + 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 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 + # validates_confirmation_of w/o mocha def test_validates_confirmation_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:confirmation => 'custom message'}}}}} @@ -121,20 +362,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + # validates_acceptance_of w/o mocha def test_validates_acceptance_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:accepted => 'custom message'}}}}} @@ -153,21 +381,8 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 - + # validates_presence_of w/o mocha + def test_validates_presence_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:blank => 'custom message'}}}}} I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:blank => 'global message'}} @@ -185,34 +400,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase assert_equal 'global message', @topic.errors.on(:title) end - - # validates_length_of :within - - def test_validates_length_of_within_generates_message_with_title_too_short - 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_title_too_short_and_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_generates_message_with_title_too_long - Topic.validates_length_of :title, :within => 3..5 - @topic.title = 'this title is too long' - @topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => nil}) - @topic.valid? - end - - def test_validates_length_of_within_generates_message_with_title_too_long_and_custom_default_message - Topic.validates_length_of :title, :within => 3..5, :too_long => 'custom' - @topic.title = 'this title is too long' - @topic.errors.expects(:generate_message).with(:title, :too_long, {:count => 5, :default => 'custom'}) - @topic.valid? - end + # validates_length_of :within w/o mocha def test_validates_length_of_within_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:too_short => 'custom message'}}}}} @@ -231,20 +419,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + # validates_length_of :is w/o mocha def test_validates_length_of_within_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} @@ -263,22 +438,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + # validates_uniqueness_of w/o mocha def test_validates_length_of_within_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:wrong_length => 'custom message'}}}}} @@ -298,21 +458,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + # validates_format_of w/o mocha def test_validates_format_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:invalid => 'custom message'}}}}} @@ -331,22 +477,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + # validates_inclusion_of w/o mocha def test_validates_inclusion_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:inclusion => 'custom message'}}}}} @@ -365,22 +496,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + # validates_exclusion_of w/o mocha def test_validates_exclusion_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:exclusion => 'custom message'}}}}} @@ -401,22 +517,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase assert_equal 'global message', @topic.errors.on(:title) end - - # validates_numericality_of without :only_integer - - def test_validates_numericality_of_generates_message - Topic.validates_numericality_of :title - @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_generates_message_with_custom_default_message - Topic.validates_numericality_of :title, :message => 'custom' - @topic.title = 'a' - @topic.errors.expects(:generate_message).with(:title, :not_a_number, {:value => 'a', :default => 'custom'}) - @topic.valid? - end + # validates_numericality_of without :only_integer w/o mocha def test_validates_numericality_of_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:not_a_number => 'custom message'}}}}} @@ -437,22 +538,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase assert_equal 'global message', @topic.errors.on(:title) end - - # validates_numericality_of with :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 + # validates_numericality_of with :only_integer w/o mocha def test_validates_numericality_of_only_integer_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:not_a_number => 'custom message'}}}}} @@ -473,22 +559,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + # validates_numericality_of :odd w/o mocha def test_validates_numericality_of_odd_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:odd => 'custom message'}}}}} @@ -509,22 +580,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + # validates_numericality_of :less_than w/o mocha def test_validates_numericality_of_less_than_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:title => {:less_than => 'custom message'}}}}} @@ -546,19 +602,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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 + # validates_associated w/o mocha def test_validates_associated_finds_custom_model_key_translation I18n.backend.store_translations 'en-US', :active_record => {:error_messages => {:custom => {:topic => {:replies => {:invalid => 'custom message'}}}}} -- cgit v1.2.3 From 8f74ba96c47e77e18ce363c8e7cd2fc9196faf7a Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 2 Jul 2008 19:21:07 +0200 Subject: remove core extensions in favor of I18n#translate and I18n#localize --- activerecord/lib/active_record/validations.rb | 6 +++--- activerecord/test/cases/validations_i18n_test.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 5bbd10394c..5245f65869 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -22,7 +22,7 @@ module ActiveRecord class << self def default_error_messages ActiveSupport::Deprecation.warn("ActiveRecord::Errors.default_error_messages has been deprecated. Please use 'active_record.error_messages'.t.") - 'active_record.error_messages'.t + I18n.translate 'active_record.error_messages' end end @@ -43,7 +43,7 @@ module ActiveRecord # 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, message = nil) - message ||= :"active_record.error_messages.invalid".t + message ||= I18n.translate :"active_record.error_messages.invalid" @errors[attribute.to_s] ||= [] @errors[attribute.to_s] << message end @@ -168,7 +168,7 @@ module ActiveRecord full_messages << message else key = :"active_record.human_attribute_names.#{@base.class.name.underscore.to_sym}.#{attr}" - attr_name = key.t(locale) || @base.class.human_attribute_name(attr) + attr_name = I18n.translate(key, locale, :raise => true) rescue @base.class.human_attribute_name(attr) full_messages << attr_name + " " + message end end diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index 53e90f4d53..840fcd81d0 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -79,7 +79,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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') + I18n.expects(:translate).with(:"active_record.human_attribute_names.topic.title", 'en-US', :raise => true).returns('Title') @topic.errors.full_messages :locale => 'en-US' end end -- cgit v1.2.3 From e1a7f83fca862fd7472ef6b80f8b6a8d33849a8e Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Fri, 4 Jul 2008 22:22:20 +0200 Subject: use :default for human_attribute_name --- activerecord/lib/active_record/validations.rb | 2 +- activerecord/test/cases/validations_i18n_test.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 5245f65869..8ba09b3992 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -168,7 +168,7 @@ module ActiveRecord full_messages << message else key = :"active_record.human_attribute_names.#{@base.class.name.underscore.to_sym}.#{attr}" - attr_name = I18n.translate(key, locale, :raise => true) rescue @base.class.human_attribute_name(attr) + attr_name = I18n.translate(key, locale, :default => @base.class.human_attribute_name(attr)) full_messages << attr_name + " " + message end end diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index 840fcd81d0..5be518c547 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -79,7 +79,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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', :raise => true).returns('Title') + I18n.expects(:translate).with(:"active_record.human_attribute_names.topic.title", 'en-US', :default => 'Title').returns('Title') @topic.errors.full_messages :locale => 'en-US' end end -- cgit v1.2.3 From 84816ae981a8598e5e401eb1b9b805de840fefc9 Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Sun, 6 Jul 2008 21:20:02 +0200 Subject: align with changes in i18n --- activerecord/lib/active_record/validations.rb | 5 ++--- activerecord/test/cases/validations_i18n_test.rb | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 8ba09b3992..a328c4d927 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -70,7 +70,7 @@ module ActiveRecord msgs << options[:default] if options[:default] msgs << key - I18n.t options.merge(:default => msgs, :scope => [:active_record, :error_messages]) + I18n.t nil, options.merge(:default => msgs, :scope => [:active_record, :error_messages]) end # Returns true if the specified +attribute+ has errors associated with it. @@ -158,7 +158,6 @@ module ActiveRecord # ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"] def full_messages(options = {}) full_messages = [] - locale = options[:locale] @errors.each_key do |attr| @errors[attr].each do |message| @@ -168,7 +167,7 @@ module ActiveRecord full_messages << message else key = :"active_record.human_attribute_names.#{@base.class.name.underscore.to_sym}.#{attr}" - attr_name = I18n.translate(key, locale, :default => @base.class.human_attribute_name(attr)) + attr_name = I18n.translate(key, :locale => options[:locale], :default => @base.class.human_attribute_name(attr)) full_messages << attr_name + " " + message end end diff --git a/activerecord/test/cases/validations_i18n_test.rb b/activerecord/test/cases/validations_i18n_test.rb index 5be518c547..86834fe920 100644 --- a/activerecord/test/cases/validations_i18n_test.rb +++ b/activerecord/test/cases/validations_i18n_test.rb @@ -46,14 +46,14 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase global_scope = [:active_record, :error_messages] custom_scope = global_scope + [:custom, 'topic', :title] - I18n.expects(:t).with :scope => [:active_record, :error_messages], :default => [:"custom.topic.title.invalid", 'default from class def', :invalid] + I18n.expects(:t).with nil, :scope => [:active_record, :error_messages], :default => [:"custom.topic.title.invalid", 'default from class def', :invalid] @topic.errors.generate_message :title, :invalid, :default => 'default from class def' end def test_errors_generate_message_translates_custom_model_attribute_keys_with_sti custom_scope = [:active_record, :error_messages, :custom, 'topic', :title] - I18n.expects(:t).with :scope => [:active_record, :error_messages], :default => [:"custom.reply.title.invalid", :"custom.topic.title.invalid", 'default from class def', :invalid] + I18n.expects(:t).with nil, :scope => [:active_record, :error_messages], :default => [:"custom.reply.title.invalid", :"custom.topic.title.invalid", 'default from class def', :invalid] Reply.new.errors.generate_message :title, :invalid, :default => 'default from class def' end @@ -79,7 +79,7 @@ class ActiveRecordValidationsI18nTests < Test::Unit::TestCase 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', :default => 'Title').returns('Title') + I18n.expects(:translate).with(:"active_record.human_attribute_names.topic.title", :locale => 'en-US', :default => 'Title').returns('Title') @topic.errors.full_messages :locale => 'en-US' end end -- cgit v1.2.3 From 826c3db42105518b3a88cf56e348b48c1660f850 Mon Sep 17 00:00:00 2001 From: Luca Guidi Date: Mon, 7 Jul 2008 22:46:16 +0200 Subject: Updated ActiveRecord::Errors#default_error_messages deprecation warning according to i18n changes --- activerecord/lib/active_record/validations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index a328c4d927..83d55f23ea 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -21,7 +21,7 @@ module ActiveRecord class << self def default_error_messages - ActiveSupport::Deprecation.warn("ActiveRecord::Errors.default_error_messages has been deprecated. Please use 'active_record.error_messages'.t.") + ActiveSupport::Deprecation.warn("ActiveRecord::Errors.default_error_messages has been deprecated. Please use I18n.translate('active_record.error_messages').") I18n.translate 'active_record.error_messages' end end -- cgit v1.2.3 From d72c66532f959846cdc2d7fb1dc1ef6ba87bdcb1 Mon Sep 17 00:00:00 2001 From: Rhett Sutphin Date: Mon, 14 Jul 2008 02:01:52 +0100 Subject: Make fixture accessors work when fixture name is not same as the table name. [#124 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/fixtures.rb | 7 ++++--- activerecord/test/cases/fixtures_test.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index e19614e31f..17fb9355c4 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -541,10 +541,11 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) label.to_s.hash.abs end - attr_reader :table_name + attr_reader :table_name, :name def initialize(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE) @connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter + @name = table_name # preserve fixture base name @class_name = class_name || (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize) @table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}" @@ -963,9 +964,9 @@ module Test #:nodoc: fixtures = Fixtures.create_fixtures(fixture_path, fixture_table_names, fixture_class_names) unless fixtures.nil? if fixtures.instance_of?(Fixtures) - @loaded_fixtures[fixtures.table_name] = fixtures + @loaded_fixtures[fixtures.name] = fixtures else - fixtures.each { |f| @loaded_fixtures[f.table_name] = f } + fixtures.each { |f| @loaded_fixtures[f.name] = f } end end end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index aca7cfb367..0ea24868f1 100755 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -15,6 +15,7 @@ require 'models/pirate' require 'models/treasure' require 'models/matey' require 'models/ship' +require 'models/book' class FixturesTest < ActiveRecord::TestCase self.use_instantiated_fixtures = true @@ -373,6 +374,34 @@ class CheckSetTableNameFixturesTest < ActiveRecord::TestCase end end +class FixtureNameIsNotTableNameFixturesTest < ActiveRecord::TestCase + set_fixture_class :items => Book + fixtures :items + # Set to false to blow away fixtures cache and ensure our fixtures are loaded + # and thus takes into account our set_fixture_class + self.use_transactional_fixtures = false + + def test_named_accessor + assert_kind_of Book, items(:dvd) + end +end + +class FixtureNameIsNotTableNameMultipleFixturesTest < ActiveRecord::TestCase + set_fixture_class :items => Book, :funny_jokes => Joke + fixtures :items, :funny_jokes + # Set to false to blow away fixtures cache and ensure our fixtures are loaded + # and thus takes into account our set_fixture_class + self.use_transactional_fixtures = false + + def test_named_accessor_of_differently_named_fixture + assert_kind_of Book, items(:dvd) + end + + def test_named_accessor_of_same_named_fixture + assert_kind_of Joke, funny_jokes(:a_joke) + end +end + class CustomConnectionFixturesTest < ActiveRecord::TestCase set_fixture_class :courses => Course fixtures :courses -- cgit v1.2.3 From c6f397c5cecf183680c191dd2128c0a96c5b9399 Mon Sep 17 00:00:00 2001 From: Jason Dew Date: Fri, 27 Jun 2008 12:25:26 -0400 Subject: Add block syntax to HasManyAssociation#build. [#502 state:resolve] Signed-off-by: Pratik Naik --- .../associations/association_collection.rb | 9 ++++--- .../associations/has_many_associations_test.rb | 31 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index eb39714909..04be59e89d 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -78,11 +78,14 @@ module ActiveRecord @loaded = false end - def build(attributes = {}) + def build(attributes = {}, &block) if attributes.is_a?(Array) - attributes.collect { |attr| build(attr) } + attributes.collect { |attr| build(attr, &block) } else - build_record(attributes) { |record| set_belongs_to_association_for(record) } + build_record(attributes) do |record| + block.call(record) if block_given? + set_belongs_to_association_for(record) + end end end diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index e90edbb213..b9c7ec6377 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -425,6 +425,37 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal 2, first_topic.replies.to_ary.size end + def test_build_via_block + company = companies(:first_firm) + new_client = assert_no_queries { company.clients_of_firm.build {|client| client.name = "Another Client" } } + assert !company.clients_of_firm.loaded? + + assert_equal "Another Client", new_client.name + assert new_client.new_record? + assert_equal new_client, company.clients_of_firm.last + company.name += '-changed' + assert_queries(2) { assert company.save } + assert !new_client.new_record? + assert_equal 2, company.clients_of_firm(true).size + end + + def test_build_many_via_block + company = companies(:first_firm) + new_clients = assert_no_queries do + company.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) do |client| + client.name = "changed" + end + end + + assert_equal 2, new_clients.size + assert_equal "changed", new_clients.first.name + assert_equal "changed", new_clients.last.name + + company.name += '-changed' + assert_queries(3) { assert company.save } + assert_equal 3, company.clients_of_firm(true).size + end + def test_create_without_loading_association first_firm = companies(:first_firm) Firm.column_names -- cgit v1.2.3 From e0750d6a5c7f621e4ca12205137c0b135cab444a Mon Sep 17 00:00:00 2001 From: David Dollar Date: Sun, 13 Jul 2008 21:13:50 -0400 Subject: Add :accessible option to Associations for allowing mass assignments using hash. [#474 state:resolved] Allows nested Hashes (i.e. from nested forms) to hydrate the appropriate ActiveRecord models. class Post < ActiveRecord::Base belongs_to :author, :accessible => true has_many :comments, :accessible => true end post = Post.create({ :title => 'Accessible Attributes', :author => { :name => 'David Dollar' }, :comments => [ { :body => 'First Post!' }, { :body => 'Nested Hashes are great!' } ] }) post.comments << { :body => 'Another Comment' } Signed-off-by: Pratik Naik --- activerecord/CHANGELOG | 18 ++++ activerecord/lib/active_record/associations.rb | 14 ++- .../associations/association_collection.rb | 6 ++ activerecord/test/cases/associations_test.rb | 108 +++++++++++++++++++++ activerecord/test/models/author.rb | 2 +- activerecord/test/models/post.rb | 6 ++ 6 files changed, 149 insertions(+), 5 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index d92b89cfe0..56b1781537 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,23 @@ *Edge* +* Add :accessible option to associations for allowing (opt-in) mass assignment. #474. [David Dollar] Example : + + class Post < ActiveRecord::Base + belongs_to :author, :accessible => true + has_many :comments, :accessible => true + end + + post = Post.create({ + :title => 'Accessible Attributes', + :author => { :name => 'David Dollar' }, + :comments => [ + { :body => 'First Post!' }, + { :body => 'Nested Hashes are great!' } + ] + }) + + post.comments << { :body => 'Another Comment' } + * Add :tokenizer option to validates_length_of to specify how to split up the attribute string. #507. [David Lowenfels] Example : # Ensure essay contains at least 100 words. diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 6931744058..d43e07ab4e 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -692,6 +692,7 @@ module ActiveRecord # * :uniq - If true, duplicates will be omitted from the collection. Useful in conjunction with :through. # * :readonly - If true, all the associated objects are readonly through the association. # * :validate - If false, don't validate the associated objects when saving the parent object. true by default. + # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # has_many :comments, :order => "posted_on" @@ -774,6 +775,7 @@ module ActiveRecord # association is a polymorphic +belongs_to+. # * :readonly - If true, the associated object is readonly through the association. # * :validate - If false, don't validate the associated object when saving the parent object. +false+ by default. + # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # has_one :credit_card, :dependent => :destroy # destroys the associated credit card @@ -863,6 +865,7 @@ module ActiveRecord # to the +attr_readonly+ list in the associated classes (e.g. class Post; attr_readonly :comments_count; end). # * :readonly - If true, the associated object is readonly through the association. # * :validate - If false, don't validate the associated objects when saving the parent object. +false+ by default. + # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # belongs_to :firm, :foreign_key => "client_of" @@ -1034,6 +1037,7 @@ module ActiveRecord # but not include the joined columns. Do not forget to include the primary and foreign keys, otherwise it will raise an error. # * :readonly - If true, all the associated objects are readonly through the association. # * :validate - If false, don't validate the associated objects when saving the parent object. +true+ by default. + # * :accessible - Mass assignment is allowed for this assocation (similar to ActiveRecord::Base#attr_accessible). # # Option examples: # has_and_belongs_to_many :projects @@ -1109,6 +1113,8 @@ module ActiveRecord association = association_proxy_class.new(self, reflection) end + new_value = reflection.klass.new(new_value) if reflection.options[:accessible] && new_value.is_a?(Hash) + if association_proxy_class == HasOneThroughAssociation association.create_through_record(new_value) self.send(reflection.name, new_value) @@ -1357,7 +1363,7 @@ module ActiveRecord :finder_sql, :counter_sql, :before_add, :after_add, :before_remove, :after_remove, :extend, :readonly, - :validate + :validate, :accessible ) options[:extend] = create_extension_modules(association_id, extension, options[:extend]) @@ -1367,7 +1373,7 @@ module ActiveRecord def create_has_one_reflection(association_id, options) options.assert_valid_keys( - :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate, :primary_key + :class_name, :foreign_key, :remote, :select, :conditions, :order, :include, :dependent, :counter_cache, :extend, :as, :readonly, :validate, :primary_key, :accessible ) create_reflection(:has_one, association_id, options, self) @@ -1383,7 +1389,7 @@ module ActiveRecord def create_belongs_to_reflection(association_id, options) options.assert_valid_keys( :class_name, :foreign_key, :foreign_type, :remote, :select, :conditions, :include, :dependent, - :counter_cache, :extend, :polymorphic, :readonly, :validate + :counter_cache, :extend, :polymorphic, :readonly, :validate, :accessible ) reflection = create_reflection(:belongs_to, association_id, options, self) @@ -1403,7 +1409,7 @@ module ActiveRecord :finder_sql, :delete_sql, :insert_sql, :before_add, :after_add, :before_remove, :after_remove, :extend, :readonly, - :validate + :validate, :accessible ) options[:extend] = create_extension_modules(association_id, extension, options[:extend]) diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 04be59e89d..a28be9eed1 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -97,6 +97,8 @@ module ActiveRecord @owner.transaction do flatten_deeper(records).each do |record| + record = @reflection.klass.new(record) if @reflection.options[:accessible] && record.is_a?(Hash) + raise_on_type_mismatch(record) add_record_to_target_with_callbacks(record) do |r| result &&= insert_record(record) unless @owner.new_record? @@ -229,6 +231,10 @@ module ActiveRecord # Replace this collection with +other_array+ # This will perform a diff and delete/add only records that have changed. def replace(other_array) + other_array.map! do |val| + val.is_a?(Hash) ? @reflection.klass.new(val) : val + end if @reflection.options[:accessible] + other_array.each { |val| raise_on_type_mismatch(val) } load_target diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 59349dd7cf..4904feeb7d 100755 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -189,6 +189,114 @@ class AssociationProxyTest < ActiveRecord::TestCase end end + def test_belongs_to_mass_assignment + post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } + author_attributes = { :name => 'David Dollar' } + + assert_no_difference 'Author.count' do + assert_raise(ActiveRecord::AssociationTypeMismatch) do + Post.create(post_attributes.merge({:author => author_attributes})) + end + end + + assert_difference 'Author.count' do + post = Post.create(post_attributes.merge({:creatable_author => author_attributes})) + assert_equal post.creatable_author.name, author_attributes[:name] + end + end + + def test_has_one_mass_assignment + post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } + comment_attributes = { :body => 'Setter Takes Hash' } + + assert_no_difference 'Comment.count' do + assert_raise(ActiveRecord::AssociationTypeMismatch) do + Post.create(post_attributes.merge({:uncreatable_comment => comment_attributes})) + end + end + + assert_difference 'Comment.count' do + post = Post.create(post_attributes.merge({:creatable_comment => comment_attributes})) + assert_equal post.creatable_comment.body, comment_attributes[:body] + end + end + + def test_has_many_mass_assignment + post = posts(:welcome) + post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } + comment_attributes = { :body => 'Setter Takes Hash' } + + assert_no_difference 'Comment.count' do + assert_raise(ActiveRecord::AssociationTypeMismatch) do + Post.create(post_attributes.merge({:comments => [comment_attributes]})) + end + assert_raise(ActiveRecord::AssociationTypeMismatch) do + post.comments << comment_attributes + end + end + + assert_difference 'Comment.count' do + post = Post.create(post_attributes.merge({:creatable_comments => [comment_attributes]})) + assert_equal post.creatable_comments.last.body, comment_attributes[:body] + end + + assert_difference 'Comment.count' do + post.creatable_comments << comment_attributes + assert_equal post.comments.last.body, comment_attributes[:body] + end + + post.creatable_comments = [comment_attributes, comment_attributes] + assert_equal post.creatable_comments.count, 2 + end + + def test_has_and_belongs_to_many_mass_assignment + post = posts(:welcome) + post_attributes = { :title => 'Associations', :body => 'Are They Accessible?' } + category_attributes = { :name => 'Accessible Association', :type => 'Category' } + + assert_no_difference 'Category.count' do + assert_raise(ActiveRecord::AssociationTypeMismatch) do + Post.create(post_attributes.merge({:categories => [category_attributes]})) + end + assert_raise(ActiveRecord::AssociationTypeMismatch) do + post.categories << category_attributes + end + end + + assert_difference 'Category.count' do + post = Post.create(post_attributes.merge({:creatable_categories => [category_attributes]})) + assert_equal post.creatable_categories.last.name, category_attributes[:name] + end + + assert_difference 'Category.count' do + post.creatable_categories << category_attributes + assert_equal post.creatable_categories.last.name, category_attributes[:name] + end + + post.creatable_categories = [category_attributes, category_attributes] + assert_equal post.creatable_categories.count, 2 + end + + def test_association_proxy_setter_can_take_hash + special_comment_attributes = { :body => 'Setter Takes Hash' } + + post = posts(:welcome) + post.creatable_comment = { :body => 'Setter Takes Hash' } + + assert_equal post.creatable_comment.body, special_comment_attributes[:body] + end + + def test_association_collection_can_take_hash + post_attributes = { :title => 'Setter Takes', :body => 'Hash' } + david = authors(:david) + + post = (david.posts << post_attributes).last + assert_equal post.title, post_attributes[:title] + + david.posts = [post_attributes, post_attributes] + assert_equal david.posts.count, 2 + end + def setup_dangling_association josh = Author.create(:name => "Josh") p = Post.create(:title => "New on Edge", :body => "More cool stuff!", :author => josh) diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb index 82e069005a..136dc39cf3 100644 --- a/activerecord/test/models/author.rb +++ b/activerecord/test/models/author.rb @@ -1,5 +1,5 @@ class Author < ActiveRecord::Base - has_many :posts + has_many :posts, :accessible => true has_many :posts_with_comments, :include => :comments, :class_name => "Post" has_many :posts_with_comments_sorted_by_comment_id, :include => :comments, :class_name => "Post", :order => 'comments.id' has_many :posts_with_categories, :include => :categories, :class_name => "Post" diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index 3adbc0ce1f..e23818eb33 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -33,6 +33,12 @@ class Post < ActiveRecord::Base has_and_belongs_to_many :categories has_and_belongs_to_many :special_categories, :join_table => "categories_posts", :association_foreign_key => 'category_id' + belongs_to :creatable_author, :class_name => 'Author', :accessible => true + has_one :uncreatable_comment, :class_name => 'Comment', :accessible => false, :order => 'id desc' + has_one :creatable_comment, :class_name => 'Comment', :accessible => true, :order => 'id desc' + has_many :creatable_comments, :class_name => 'Comment', :accessible => true, :dependent => :destroy + has_and_belongs_to_many :creatable_categories, :class_name => 'Category', :accessible => true + has_many :taggings, :as => :taggable has_many :tags, :through => :taggings do def add_joins_and_select -- cgit v1.2.3 From 0176e6adb388998414083e99523de318d3b8ca49 Mon Sep 17 00:00:00 2001 From: "Sebastian A. Espindola" Date: Tue, 8 Jul 2008 01:14:11 -0300 Subject: Added db:charset support to PostgreSQL. [#556 state:resolved] Signed-off-by: Pratik Naik --- .../active_record/connection_adapters/postgresql_adapter.rb | 13 +++++++++++++ activerecord/test/cases/adapter_test.rb | 6 ++++++ 2 files changed, 19 insertions(+) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 2e2d50ccf4..29ecd83ba0 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -623,6 +623,19 @@ module ActiveRecord end end + # Returns the current database name. + def current_database + query('select current_database()')[0][0] + end + + # Returns the current database encoding format. + def encoding + query(<<-end_sql)[0][0] + SELECT pg_encoding_to_char(pg_database.encoding) FROM pg_database + WHERE pg_database.datname LIKE '#{current_database}' + end_sql + end + # Sets the schema search path to a string of comma-separated schema names. # Names beginning with $ have to be quoted (e.g. $user => '$user'). # See: http://www.postgresql.org/docs/current/static/ddl-schemas.html diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 11f9870534..04770646b2 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -65,6 +65,12 @@ class AdapterTest < ActiveRecord::TestCase end end + if current_adapter?(:PostgreSQLAdapter) + def test_encoding + assert_not_nil @connection.encoding + end + end + def test_table_alias def @connection.test_table_alias_length() 10; end class << @connection -- cgit v1.2.3 From 30370227890dc950f1544b7b1040aa75e505f877 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 14 Jul 2008 10:12:54 -0500 Subject: Fixed that create database statements would always include "DEFAULT NULL" (Nick Sieger) [#334 status:committed] --- activerecord/CHANGELOG | 2 ++ .../abstract/schema_definitions.rb | 5 ++- activerecord/test/cases/column_definition_test.rb | 36 ++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 activerecord/test/cases/column_definition_test.rb (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 56b1781537..17430ba0b7 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Fixed that create database statements would always include "DEFAULT NULL" (Nick Sieger) [#334] + * Add :accessible option to associations for allowing (opt-in) mass assignment. #474. [David Dollar] Example : class Post < ActiveRecord::Base diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index d4c8a80448..13ccfea0b8 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -257,7 +257,10 @@ module ActiveRecord def to_sql column_sql = "#{base.quote_column_name(name)} #{sql_type}" - add_column_options!(column_sql, :null => null, :default => default) unless type.to_sym == :primary_key + column_options = {} + column_options[:null] = null unless null.nil? + column_options[:default] = default unless default.nil? + add_column_options!(column_sql, column_options) unless type.to_sym == :primary_key column_sql end alias to_s :to_sql diff --git a/activerecord/test/cases/column_definition_test.rb b/activerecord/test/cases/column_definition_test.rb new file mode 100644 index 0000000000..540f42f4b6 --- /dev/null +++ b/activerecord/test/cases/column_definition_test.rb @@ -0,0 +1,36 @@ +require "cases/helper" + +class ColumnDefinitionTest < ActiveRecord::TestCase + def setup + @adapter = ActiveRecord::ConnectionAdapters::AbstractAdapter.new(nil) + def @adapter.native_database_types + {:string => "varchar"} + end + end + + # Avoid column definitions in create table statements like: + # `title` varchar(255) DEFAULT NULL NULL + def test_should_not_include_default_clause_when_default_is_null + column = ActiveRecord::ConnectionAdapters::Column.new("title", nil, "varchar(20)") + column_def = ActiveRecord::ConnectionAdapters::ColumnDefinition.new( + @adapter, column.name, "string", + column.limit, column.precision, column.scale, column.default, column.null) + assert_equal "title varchar(20) NULL", column_def.to_sql + end + + def test_should_include_default_clause_when_default_is_present + column = ActiveRecord::ConnectionAdapters::Column.new("title", "Hello", "varchar(20)") + column_def = ActiveRecord::ConnectionAdapters::ColumnDefinition.new( + @adapter, column.name, "string", + column.limit, column.precision, column.scale, column.default, column.null) + assert_equal %Q{title varchar(20) DEFAULT 'Hello' NULL}, column_def.to_sql + end + + def test_should_specify_not_null_if_null_option_is_false + column = ActiveRecord::ConnectionAdapters::Column.new("title", "Hello", "varchar(20)", false) + column_def = ActiveRecord::ConnectionAdapters::ColumnDefinition.new( + @adapter, column.name, "string", + column.limit, column.precision, column.scale, column.default, column.null) + assert_equal %Q{title varchar(20) DEFAULT 'Hello' NOT NULL}, column_def.to_sql + end +end \ No newline at end of file -- cgit v1.2.3 From cdf0f1aa2ee4ba73bafc9b9217ee35b7f7eb3273 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Sat, 12 Jul 2008 11:42:17 -0700 Subject: Faster and clearer value_to_boolean --- .../connection_adapters/abstract/schema_definitions.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 13ccfea0b8..31d6c7942c 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -1,4 +1,5 @@ require 'date' +require 'set' require 'bigdecimal' require 'bigdecimal/util' @@ -6,6 +7,8 @@ module ActiveRecord module ConnectionAdapters #:nodoc: # An abstract definition of a column in a table. class Column + TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set + module Format ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/ ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/ @@ -135,11 +138,7 @@ module ActiveRecord # convert something to a boolean def value_to_boolean(value) - if value == true || value == false - value - else - !(value.to_s !~ /\A(?:1|t|true)\Z/i) - end + TRUE_VALUES.include?(value) end # convert something to a BigDecimal -- cgit v1.2.3 From c760dbfd3117562c6f27170a213f586e3ba2b794 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 14 Jul 2008 11:59:46 -0700 Subject: PostgreSQL: don't dump :limit => 4 for integers --- activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 29ecd83ba0..6d16d72dea 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -49,7 +49,6 @@ module ActiveRecord private def extract_limit(sql_type) case sql_type - when /^integer/i; 4 when /^bigint/i; 8 when /^smallint/i; 2 else super -- cgit v1.2.3 From 8f72bc92e20b1242272714f253e23b256761ec1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Mon, 14 Jul 2008 09:40:05 +0300 Subject: Fixed test_rename_nonexistent_column for PostgreSQL Also fixed ability to run migration_test.rb alone [#616 state:resolved] --- activerecord/test/cases/migration_test.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 4482b487dd..f9a2d9c47c 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -3,6 +3,7 @@ require 'bigdecimal/util' require 'models/person' require 'models/topic' +require 'models/developer' require MIGRATIONS_ROOT + "/valid/1_people_have_last_names" require MIGRATIONS_ROOT + "/valid/2_we_need_reminders" @@ -511,7 +512,12 @@ if ActiveRecord::Base.connection.supports_migrations? ActiveRecord::Base.connection.create_table(:hats) do |table| table.column :hat_name, :string, :default => nil end - assert_raises(ActiveRecord::ActiveRecordError) do + exception = if current_adapter?(:PostgreSQLAdapter) + ActiveRecord::StatementInvalid + else + ActiveRecord::ActiveRecordError + end + assert_raises(exception) do Person.connection.rename_column "hats", "nonexistent", "should_fail" end ensure -- cgit v1.2.3 From 07578ac85585d3c64d4d38d4892fd31582c7c473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Mon, 14 Jul 2008 09:42:20 +0300 Subject: Fixed mysql change_column_default to not make the column always nullable. Also added change_column_null to both mysql and sqlite to keep the api features closer to postgresql. [#617 state:resolved] --- activerecord/CHANGELOG | 2 + .../connection_adapters/mysql_adapter.rb | 33 +++++++++++---- .../connection_adapters/sqlite_adapter.rb | 9 ++++ activerecord/test/cases/migration_test.rb | 49 ++++++++++++++++++++++ 4 files changed, 86 insertions(+), 7 deletions(-) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 17430ba0b7..95fdd93f65 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* change_column_default preserves the not-null constraint. #617 [Tarmo Tänav] + * Fixed that create database statements would always include "DEFAULT NULL" (Nick Sieger) [#334] * Add :accessible option to associations for allowing (opt-in) mass assignment. #474. [David Dollar] Example : diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 4b13ac8be0..35b9ed4746 100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -437,18 +437,29 @@ module ActiveRecord end def change_column_default(table_name, column_name, default) #:nodoc: - current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] + column = column_for(table_name, column_name) + change_column table_name, column_name, column.sql_type, :default => default + end + + def change_column_null(table_name, column_name, null, default = nil) + column = column_for(table_name, column_name) + + unless null || default.nil? + execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") + end - execute("ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{current_type} DEFAULT #{quote(default)}") + change_column table_name, column_name, column.sql_type, :null => null end def change_column(table_name, column_name, type, options = {}) #:nodoc: + column = column_for(table_name, column_name) + unless options_include_default?(options) - if column = columns(table_name).find { |c| c.name == column_name.to_s } - options[:default] = column.default - else - raise "No such column: #{table_name}.#{column_name}" - end + options[:default] = column.default + end + + unless options.has_key?(:null) + options[:null] = column.null end change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" @@ -460,6 +471,7 @@ module ActiveRecord options = {} if column = columns(table_name).find { |c| c.name == column_name.to_s } options[:default] = column.default + options[:null] = column.null else raise ActiveRecordError, "No such column: #{table_name}.#{column_name}" end @@ -536,6 +548,13 @@ module ActiveRecord def version @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } end + + def column_for(table_name, column_name) + unless column = columns(table_name).find { |c| c.name == column_name.to_s } + raise "No such column: #{table_name}.#{column_name}" + end + column + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index 51cfd10e5c..f4d387cfb4 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -238,6 +238,15 @@ module ActiveRecord end end + def change_column_null(table_name, column_name, null, default = nil) + unless null || default.nil? + execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") + end + alter_table(table_name) do |definition| + definition[column_name].null = null + end + end + def change_column(table_name, column_name, type, options = {}) #:nodoc: alter_table(table_name) do |definition| include_default = options_include_default?(options) diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index f9a2d9c47c..7ecf755ef8 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -703,6 +703,55 @@ if ActiveRecord::Base.connection.supports_migrations? Person.connection.drop_table :testings rescue nil end + def test_keeping_default_and_notnull_constaint_on_change + Person.connection.create_table :testings do |t| + t.column :title, :string + end + person_klass = Class.new(Person) + person_klass.set_table_name 'testings' + + person_klass.connection.add_column "testings", "wealth", :integer, :null => false, :default => 99 + person_klass.reset_column_information + assert_equal 99, person_klass.columns_hash["wealth"].default + assert_equal false, person_klass.columns_hash["wealth"].null + assert_nothing_raised {person_klass.connection.execute("insert into testings (title) values ('tester')")} + + # change column default to see that column doesn't lose its not null definition + person_klass.connection.change_column_default "testings", "wealth", 100 + person_klass.reset_column_information + assert_equal 100, person_klass.columns_hash["wealth"].default + assert_equal false, person_klass.columns_hash["wealth"].null + + # rename column to see that column doesn't lose its not null and/or default definition + person_klass.connection.rename_column "testings", "wealth", "money" + person_klass.reset_column_information + assert_nil person_klass.columns_hash["wealth"] + assert_equal 100, person_klass.columns_hash["money"].default + assert_equal false, person_klass.columns_hash["money"].null + + # change column + person_klass.connection.change_column "testings", "money", :integer, :null => false, :default => 1000 + person_klass.reset_column_information + assert_equal 1000, person_klass.columns_hash["money"].default + assert_equal false, person_klass.columns_hash["money"].null + + # change column, make it nullable and clear default + person_klass.connection.change_column "testings", "money", :integer, :null => true, :default => nil + person_klass.reset_column_information + assert_nil person_klass.columns_hash["money"].default + assert_equal true, person_klass.columns_hash["money"].null + + # change_column_null, make it not nullable and set null values to a default value + person_klass.connection.execute('UPDATE testings SET money = NULL') + person_klass.connection.change_column_null "testings", "money", false, 2000 + person_klass.reset_column_information + assert_nil person_klass.columns_hash["money"].default + assert_equal false, person_klass.columns_hash["money"].null + assert_equal [2000], Person.connection.select_values("SELECT money FROM testings").map { |s| s.to_i }.sort + ensure + Person.connection.drop_table :testings rescue nil + end + def test_change_column_default_to_null Person.connection.change_column_default "people", "first_name", nil Person.reset_column_information -- cgit v1.2.3 From cd9b24286a90111a08002e0da753198c5fb2432a Mon Sep 17 00:00:00 2001 From: Gabe da Silveira Date: Tue, 3 Jun 2008 17:50:42 -0300 Subject: Add assert_sql helper method to check for specific SQL output in Active Record test suite. [#325 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/test_case.rb | 15 +++++++++++++-- activerecord/test/cases/helper.rb | 10 +++++----- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/test_case.rb b/activerecord/lib/active_record/test_case.rb index 7dee962c8a..ca5591ae35 100644 --- a/activerecord/lib/active_record/test_case.rb +++ b/activerecord/lib/active_record/test_case.rb @@ -22,11 +22,22 @@ module ActiveRecord end end + def assert_sql(*patterns_to_match) + $queries_executed = [] + yield + ensure + failed_patterns = [] + patterns_to_match.each do |pattern| + failed_patterns << pattern unless $queries_executed.any?{ |sql| pattern === sql } + end + assert failed_patterns.empty?, "Query pattern(s) #{failed_patterns.map(&:inspect).join(', ')} not found." + end + def assert_queries(num = 1) - $query_count = 0 + $queries_executed = [] yield ensure - assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed." + assert_equal num, $queries_executed.size, "#{$queries_executed.size} instead of #{num} queries were executed." end def assert_no_queries(&block) diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index dc83300efa..0530ba9bd9 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -32,13 +32,13 @@ end ActiveRecord::Base.connection.class.class_eval do IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/] - def execute_with_counting(sql, name = nil, &block) - $query_count ||= 0 - $query_count += 1 unless IGNORED_SQL.any? { |r| sql =~ r } - execute_without_counting(sql, name, &block) + def execute_with_query_record(sql, name = nil, &block) + $queries_executed ||= [] + $queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r } + execute_without_query_record(sql, name, &block) end - alias_method_chain :execute, :counting + alias_method_chain :execute, :query_record end # Make with_scope public for tests -- cgit v1.2.3 From 76df9fa0680d62ce41fa6f3b743c605101d101d2 Mon Sep 17 00:00:00 2001 From: Tiago Macedo Date: Fri, 11 Jul 2008 04:18:41 +0100 Subject: Fix integer quoting issues in association preload. [#602 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/association_preload.rb | 15 ++++++++++++--- activerecord/test/cases/inheritance_test.rb | 7 +++++++ 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 49f5270396..174ec95de2 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -188,7 +188,6 @@ module ActiveRecord through_records end - # FIXME: quoting def preload_belongs_to_association(records, reflection, preload_options={}) options = reflection.options primary_key_name = reflection.primary_key_name @@ -227,9 +226,19 @@ module ActiveRecord table_name = klass.quoted_table_name primary_key = klass.primary_key - conditions = "#{table_name}.#{primary_key} IN (?)" + conditions = "#{table_name}.#{connection.quote_column_name(primary_key)} IN (?)" conditions << append_conditions(options, preload_options) - associated_records = klass.find(:all, :conditions => [conditions, id_map.keys.uniq], + column_type = klass.columns.detect{|c| c.name == primary_key}.type + ids = id_map.keys.uniq.map do |id| + if column_type == :integer + id.to_i + elsif column_type == :float + id.to_f + else + id + end + end + associated_records = klass.find(:all, :conditions => [conditions, ids], :include => options[:include], :select => options[:select], :joins => options[:joins], diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 47fb5c608f..4fd38bfbc9 100755 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -191,6 +191,13 @@ class InheritanceTest < ActiveRecord::TestCase assert_not_nil account.instance_variable_get("@firm"), "nil proves eager load failed" end + def test_eager_load_belongs_to_primary_key_quoting + con = Account.connection + assert_sql(/\(#{con.quote_table_name('companies')}.#{con.quote_column_name('id')} IN \(1\)\)/) do + Account.find(1, :include => :firm) + end + end + def test_alt_eager_loading switch_to_alt_inheritance_column test_eager_load_belongs_to_something_inherited -- cgit v1.2.3 From 8c91b767c0f36e9d767eb230ec42b111e57d90da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Tue, 15 Jul 2008 05:17:06 +0300 Subject: Fixed postgresql limited eager loading for the case where scoped :order was present --- activerecord/lib/active_record/associations.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index d43e07ab4e..7ad7802cbc 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1486,10 +1486,15 @@ module ActiveRecord join_dependency.joins_for_table_name(table) }.flatten.compact.uniq + order = options[:order] + if scoped_order = (scope && scope[:order]) + order = order ? "#{order}, #{scoped_order}" : scoped_order + end + is_distinct = !options[:joins].blank? || include_eager_conditions?(options, tables_from_conditions) || include_eager_order?(options, tables_from_order) sql = "SELECT " if is_distinct - sql << connection.distinct("#{connection.quote_table_name table_name}.#{primary_key}", options[:order]) + sql << connection.distinct("#{connection.quote_table_name table_name}.#{primary_key}", order) else sql << primary_key end @@ -1503,8 +1508,8 @@ module ActiveRecord add_conditions!(sql, options[:conditions], scope) add_group!(sql, options[:group], scope) - if options[:order] && is_distinct - connection.add_order_by_for_association_limiting!(sql, options) + if order && is_distinct + connection.add_order_by_for_association_limiting!(sql, :order => order) else add_order!(sql, options[:order], scope) end -- cgit v1.2.3 From c1531ae00dbd3ac804bce02733e050ec43400607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarmo=20T=C3=A4nav?= Date: Tue, 15 Jul 2008 05:24:24 +0300 Subject: SQLite: rename_column raises if the column doesn't exist. [#622 state:resolved] --- activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index f4d387cfb4..84f8c0284e 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -260,6 +260,9 @@ module ActiveRecord end def rename_column(table_name, column_name, new_column_name) #:nodoc: + unless columns(table_name).detect{|c| c.name == column_name.to_s } + raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}" + end alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s}) end -- cgit v1.2.3 From 4f72feb84c25b54f66c7192c788b7fd965f2d493 Mon Sep 17 00:00:00 2001 From: Jonathan Viney Date: Wed, 2 Jul 2008 16:01:26 +1200 Subject: Move the transaction counter to the connection object rather than maintaining it on the current Thread. Signed-off-by: Michael Koziarski [#533 state:resolved] --- .../connection_adapters/abstract_adapter.rb | 13 +++++++++++ activerecord/lib/active_record/fixtures.rb | 8 +++---- activerecord/lib/active_record/transactions.rb | 17 +++------------ activerecord/test/cases/fixtures_test.rb | 6 +++--- activerecord/test/cases/multiple_db_test.rb | 25 ++++++++++++++++++++++ 5 files changed, 48 insertions(+), 21 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index f48b107a2a..47dbf5a5f3 100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -118,6 +118,19 @@ module ActiveRecord @connection end + def open_transactions + @open_transactions ||= 0 + end + + def increment_open_transactions + @open_transactions ||= 0 + @open_transactions += 1 + end + + def decrement_open_transactions + @open_transactions -= 1 + end + def log_info(sql, name, runtime) if @logger && @logger.debug? name = "#{name.nil? ? "SQL" : name} (#{sprintf("%f", runtime)})" diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 17fb9355c4..622cfc3c3f 100755 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -515,7 +515,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash) all_loaded_fixtures.update(fixtures_map) - connection.transaction(Thread.current['open_transactions'].to_i == 0) do + connection.transaction(connection.open_transactions.zero?) do fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures } fixtures.each { |fixture| fixture.insert_fixtures } @@ -930,7 +930,7 @@ module Test #:nodoc: load_fixtures @@already_loaded_fixtures[self.class] = @loaded_fixtures end - ActiveRecord::Base.send :increment_open_transactions + ActiveRecord::Base.connection.increment_open_transactions ActiveRecord::Base.connection.begin_db_transaction # Load fixtures for every test. else @@ -951,9 +951,9 @@ module Test #:nodoc: end # Rollback changes if a transaction is active. - if use_transactional_fixtures? && Thread.current['open_transactions'] != 0 + if use_transactional_fixtures? && ActiveRecord::Base.connection.open_transactions != 0 ActiveRecord::Base.connection.rollback_db_transaction - Thread.current['open_transactions'] = 0 + ActiveRecord::Base.connection.decrement_open_transactions end ActiveRecord::Base.verify_active_connections! end diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb index 3b6835762c..354a6c83a2 100644 --- a/activerecord/lib/active_record/transactions.rb +++ b/activerecord/lib/active_record/transactions.rb @@ -73,25 +73,14 @@ module ActiveRecord # trigger a ROLLBACK when raised, but not be re-raised by the transaction block. module ClassMethods def transaction(&block) - increment_open_transactions + connection.increment_open_transactions begin - connection.transaction(Thread.current['start_db_transaction'], &block) + connection.transaction(connection.open_transactions == 1, &block) ensure - decrement_open_transactions + connection.decrement_open_transactions end end - - private - def increment_open_transactions #:nodoc: - open = Thread.current['open_transactions'] ||= 0 - Thread.current['start_db_transaction'] = open.zero? - Thread.current['open_transactions'] = open + 1 - end - - def decrement_open_transactions #:nodoc: - Thread.current['open_transactions'] -= 1 - end end def transaction(&block) diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index 0ea24868f1..6ba7597f56 100755 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -461,11 +461,11 @@ class FixturesBrokenRollbackTest < ActiveRecord::TestCase alias_method :teardown, :blank_teardown def test_no_rollback_in_teardown_unless_transaction_active - assert_equal 0, Thread.current['open_transactions'] + assert_equal 0, ActiveRecord::Base.connection.open_transactions assert_raise(RuntimeError) { ar_setup_fixtures } - assert_equal 0, Thread.current['open_transactions'] + assert_equal 0, ActiveRecord::Base.connection.open_transactions assert_nothing_raised { ar_teardown_fixtures } - assert_equal 0, Thread.current['open_transactions'] + assert_equal 0, ActiveRecord::Base.connection.open_transactions end private diff --git a/activerecord/test/cases/multiple_db_test.rb b/activerecord/test/cases/multiple_db_test.rb index eb3e43c8ac..7c3e0f2ca6 100644 --- a/activerecord/test/cases/multiple_db_test.rb +++ b/activerecord/test/cases/multiple_db_test.rb @@ -57,4 +57,29 @@ class MultipleDbTest < ActiveRecord::TestCase assert Course.connection end + + def test_transactions_across_databases + c1 = Course.find(1) + e1 = Entrant.find(1) + + begin + Course.transaction do + Entrant.transaction do + c1.name = "Typo" + e1.name = "Typo" + c1.save + e1.save + raise "No I messed up." + end + end + rescue + # Yup caught it + end + + assert_equal "Typo", c1.name + assert_equal "Typo", e1.name + + assert_equal "Ruby Development", Course.find(1).name + assert_equal "Ruby Developer", Entrant.find(1).name + end end -- cgit v1.2.3 From 459e5817a513b95741b77af26771a6252a13d01f Mon Sep 17 00:00:00 2001 From: miloops Date: Thu, 26 Jun 2008 13:46:33 -0300 Subject: update_counters should update nil values. This allows counter columns with default null instead of requiring default 0. [#493 state:resolved] --- activerecord/lib/active_record/base.rb | 2 +- activerecord/test/cases/base_test.rb | 21 +++++++++++++++++++-- activerecord/test/schema/schema.rb | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 962c2b36d9..8ca5a85ad8 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -828,7 +828,7 @@ module ActiveRecord #:nodoc: def update_counters(id, counters) updates = counters.inject([]) { |list, (counter_name, increment)| sign = increment < 0 ? "-" : "+" - list << "#{connection.quote_column_name(counter_name)} = #{connection.quote_column_name(counter_name)} #{sign} #{increment.abs}" + list << "#{connection.quote_column_name(counter_name)} = COALESCE(#{connection.quote_column_name(counter_name)}, 0) #{sign} #{increment.abs}" }.join(", ") update_all(updates, "#{connection.quote_column_name(primary_key)} = #{quote_value(id)}") end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index a4be629fbd..9e4f268db7 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -19,6 +19,7 @@ require 'models/warehouse_thing' require 'rexml/document' class Category < ActiveRecord::Base; end +class Categorization < ActiveRecord::Base; end class Smarts < ActiveRecord::Base; end class CreditCard < ActiveRecord::Base class PinNumber < ActiveRecord::Base @@ -75,7 +76,7 @@ class TopicWithProtectedContentAndAccessibleAuthorName < ActiveRecord::Base end class BasicsTest < ActiveRecord::TestCase - fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors + fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations def test_table_exists assert !NonExistentTable.table_exists? @@ -130,7 +131,7 @@ class BasicsTest < ActiveRecord::TestCase def test_read_attributes_before_type_cast category = Category.new({:name=>"Test categoty", :type => nil}) - category_attrs = {"name"=>"Test categoty", "type" => nil} + category_attrs = {"name"=>"Test categoty", "type" => nil, "categorizations_count" => nil} assert_equal category_attrs , category.attributes_before_type_cast end @@ -614,6 +615,22 @@ class BasicsTest < ActiveRecord::TestCase assert_equal -2, Topic.find(2).replies_count end + def test_update_counter + category = Category.first + assert_nil category.categorizations_count + assert_equal 2, category.categorizations.count + + Category.update_counters(category.id, "categorizations_count" => category.categorizations.count) + category.reload + assert_not_nil category.categorizations_count + assert_equal 2, category.categorizations_count + + Category.update_counters(category.id, "categorizations_count" => category.categorizations.count) + category.reload + assert_not_nil category.categorizations_count + assert_equal 4, category.categorizations_count + end + def test_update_all assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'") assert_equal "bulk updated!", Topic.find(1).content diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 29c91a4464..487a08f4ab 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -66,6 +66,7 @@ ActiveRecord::Schema.define do create_table :categories, :force => true do |t| t.string :name, :null => false t.string :type + t.integer :categorizations_count end create_table :categories_posts, :force => true, :id => false do |t| -- cgit v1.2.3 From fbef982e4b906b879240a35a1ecff447007da6b2 Mon Sep 17 00:00:00 2001 From: Stefan Kaes Date: Tue, 15 Jul 2008 20:55:14 +0200 Subject: Observers not longer add an after_find method to the observed class. [#625 state:resolved] --- activerecord/lib/active_record/observer.rb | 9 ++++----- activerecord/test/cases/lifecycle_test.rb | 12 ++++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index 25e0e61c69..c96e5f9d51 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -20,7 +20,7 @@ module ActiveRecord # ActiveRecord::Base.observers = Cacher, GarbageCollector # # Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is - # called during startup, and before each development request. + # called during startup, and before each development request. def observers=(*observers) @observers = observers.flatten end @@ -130,11 +130,11 @@ module ActiveRecord # Observers register themselves in the model class they observe, since it is the class that # notifies them of events when they occur. As a side-effect, when an observer is loaded its # corresponding model class is loaded. - # + # # Up to (and including) Rails 2.0.2 observers were instantiated between plugins and - # application initializers. Now observers are loaded after application initializers, + # application initializers. Now observers are loaded after application initializers, # so observed models can make use of extensions. - # + # # If by any chance you are using observed models in the initialization you can still # load their observers by calling ModelObserver.instance before. Observers are # singletons and that call instantiates and registers them. @@ -189,7 +189,6 @@ module ActiveRecord def add_observer!(klass) klass.add_observer(self) - klass.class_eval 'def after_find() end' unless klass.method_defined?(:after_find) end end end diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb index 258f7c7a0f..3432abee31 100755 --- a/activerecord/test/cases/lifecycle_test.rb +++ b/activerecord/test/cases/lifecycle_test.rb @@ -143,12 +143,20 @@ class LifecycleTest < ActiveRecord::TestCase assert_equal developer.name, multi_observer.record.name end - def test_observing_after_find_when_not_defined_on_the_model + def test_after_find_cannot_be_observed_when_its_not_defined_on_the_model observer = MinimalisticObserver.instance assert_equal Minimalistic, MinimalisticObserver.observed_class minimalistic = Minimalistic.find(1) - assert_equal minimalistic, observer.minimalistic + assert_nil observer.minimalistic + end + + def test_after_find_can_be_observed_when_its_defined_on_the_model + observer = TopicObserver.instance + assert_equal Topic, TopicObserver.observed_class + + topic = Topic.find(1) + assert_equal topic, observer.topic end def test_invalid_observer -- cgit v1.2.3 From 2e74ddbd73cb4212afbad3907f0130c6ec38572f Mon Sep 17 00:00:00 2001 From: Sven Fuchs Date: Wed, 16 Jul 2008 04:35:00 +0200 Subject: missed to remove a call to to_s while resolving conflicts in validations.rb --- activerecord/lib/active_record/validations.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 38b2f38a3d..25eecaf49f 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -877,7 +877,7 @@ module ActiveRecord raw_value = raw_value.to_i else begin - raw_value = Kernel.Float(raw_value.to_s) + raw_value = Kernel.Float(raw_value) rescue ArgumentError, TypeError message = record.errors.generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message]) record.errors.add(attr_name, message) -- cgit v1.2.3 From 0432d151647f2178ddee79979827d552447c251f Mon Sep 17 00:00:00 2001 From: Pratik Naik Date: Wed, 16 Jul 2008 13:00:36 +0100 Subject: Merge with docrails. --- .../lib/active_record/association_preload.rb | 2 +- activerecord/lib/active_record/associations.rb | 7 ++-- activerecord/lib/active_record/base.rb | 9 ++-- activerecord/lib/active_record/callbacks.rb | 2 +- .../abstract/schema_statements.rb | 2 +- .../connection_adapters/postgresql_adapter.rb | 2 +- activerecord/lib/active_record/dirty.rb | 12 +++--- activerecord/lib/active_record/validations.rb | 48 +++++++++++----------- 8 files changed, 42 insertions(+), 42 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 174ec95de2..64888f9110 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -34,7 +34,7 @@ module ActiveRecord class_to_reflection = {} # Not all records have the same class, so group then preload # group on the reflection itself so that if various subclass share the same association then we do not split them - # unncessarily + # unnecessarily records.group_by {|record| class_to_reflection[record.class] ||= record.class.reflections[association]}.each do |reflection, records| raise ConfigurationError, "Association named '#{ association }' was not found; perhaps you misspelled it?" unless reflection send("preload_#{reflection.macro}_association", records, reflection, preload_options) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 7ad7802cbc..fd9a443eb9 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -582,12 +582,13 @@ module ActiveRecord # has_many :clients # end # - # class Company < ActiveRecord::Base; end + # class Client < ActiveRecord::Base; end # end # end # - # When Firm#clients is called, it will in turn call MyApplication::Business::Company.find(firm.id). If you want to associate - # with a class in another module scope, this can be done by specifying the complete class name. Example: + # When Firm#clients is called, it will in turn call MyApplication::Business::Client.find_all_by_firm_id(firm.id). + # If you want to associate with a class in another module scope, this can be done by specifying the complete class name. + # Example: # # module MyApplication # module Business diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 8ca5a85ad8..a75e1a5b24 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -6,7 +6,7 @@ module ActiveRecord #:nodoc: class ActiveRecordError < StandardError end - # Raised when the single-table inheritance mechanism failes to locate the subclass + # Raised when the single-table inheritance mechanism fails to locate the subclass # (for example due to improper usage of column that +inheritance_column+ points to). class SubclassNotFound < ActiveRecordError #:nodoc: end @@ -97,7 +97,7 @@ module ActiveRecord #:nodoc: class MissingAttributeError < NoMethodError end - # Raised when an error occured while doing a mass assignment to an attribute through the + # Raised when an error occurred while doing a mass assignment to an attribute through the # attributes= method. The exception has an +attribute+ property that is the name of the # offending attribute. class AttributeAssignmentError < ActiveRecordError @@ -271,7 +271,7 @@ module ActiveRecord #:nodoc: # # Now 'Bob' exist and is an 'admin' # User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true } # - # Use the find_or_initialize_by_ finder if you want to return a new record without saving it first. Protected attributes won't be setted unless they are given in a block. For example: + # Use the find_or_initialize_by_ finder if you want to return a new record without saving it first. Protected attributes won't be set unless they are given in a block. For example: # # # No 'Winter' tag exists # winter = Tag.find_or_initialize_by_name("Winter") @@ -724,8 +724,7 @@ module ActiveRecord #:nodoc: # ==== Attributes # # * +updates+ - A String of column and value pairs that will be set on any records that match conditions. - # * +conditions+ - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. - # See conditions in the intro for more info. + # * +conditions+ - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro for more info. # * +options+ - Additional options are :limit and/or :order, see the examples for usage. # # ==== Examples diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb index 1e385fb128..be2621fdb6 100755 --- a/activerecord/lib/active_record/callbacks.rb +++ b/activerecord/lib/active_record/callbacks.rb @@ -50,7 +50,7 @@ module ActiveRecord # # == Inheritable callback queues # - # Besides the overwriteable callback methods, it's also possible to register callbacks through the use of the callback macros. + # Besides the overwritable callback methods, it's also possible to register callbacks through the use of the callback macros. # Their main advantage is that the macros add behavior into a callback queue that is kept intact down through an inheritance # hierarchy. Example: # diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 7d8530ebef..0f60a91ef1 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -383,7 +383,7 @@ module ActiveRecord def add_column_options!(sql, options) #:nodoc: sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options) - # must explcitly check for :null to allow change_column to work on migrations + # must explicitly check for :null to allow change_column to work on migrations if options.has_key? :null if options[:null] == false sql << " NOT NULL" diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 6d16d72dea..6a20f41a4b 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -867,7 +867,7 @@ module ActiveRecord end private - # The internal PostgreSQL identifer of the money data type. + # The internal PostgreSQL identifier of the money data type. MONEY_COLUMN_TYPE_OID = 790 #:nodoc: # Connects to a PostgreSQL server and sets up the adapter depending on the diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb index a7d767486c..4ce0356457 100644 --- a/activerecord/lib/active_record/dirty.rb +++ b/activerecord/lib/active_record/dirty.rb @@ -62,7 +62,7 @@ module ActiveRecord changed_attributes.keys end - # Map of changed attrs => [original value, new value] + # Map of changed attrs => [original value, new value]. # person.changes # => {} # person.name = 'bob' # person.changes # => { 'name' => ['bill', 'bob'] } @@ -93,27 +93,27 @@ module ActiveRecord end private - # Map of change attr => original value. + # Map of change attr => original value. def changed_attributes @changed_attributes ||= {} end - # Handle *_changed? for method_missing. + # Handle *_changed? for +method_missing+. def attribute_changed?(attr) changed_attributes.include?(attr) end - # Handle *_change for method_missing. + # Handle *_change for +method_missing+. def attribute_change(attr) [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr) end - # Handle *_was for method_missing. + # Handle *_was for +method_missing+. def attribute_was(attr) attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr) end - # Handle *_will_change! for method_missing. + # Handle *_will_change! for +method_missing+. def attribute_will_change!(attr) changed_attributes[attr] = clone_attribute_value(:read_attribute, attr) end diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 1035308aa5..2647fbba92 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -1,5 +1,5 @@ module ActiveRecord - # Raised by save! and create! when the record is invalid. Use the + # Raised by save! and create! when the record is invalid. Use the # +record+ method to retrieve the record which did not validate. # begin # complex_operation_that_calls_save!_internally @@ -52,7 +52,7 @@ module ActiveRecord # Adds an error to the base object instead of any particular attribute. This is used # to report errors that don't tie to any specific attribute, but rather to the object # as a whole. These error messages don't get prepended with any field name when iterating - # with each_full, so they should be complete sentences. + # with +each_full+, so they should be complete sentences. def add_to_base(msg) add(:base, msg) end @@ -97,7 +97,7 @@ module ActiveRecord !@errors[attribute.to_s].nil? end - # Returns nil, if no errors are associated with the specified +attribute+. + # Returns +nil+, if no errors are associated with the specified +attribute+. # Returns the error message, if one error is associated with the specified +attribute+. # Returns an array of error messages, if more than one error is associated with the specified +attribute+. # @@ -118,7 +118,7 @@ module ActiveRecord alias :[] :on - # Returns errors assigned to the base object through add_to_base according to the normal rules of on(attribute). + # Returns errors assigned to the base object through +add_to_base+ according to the normal rules of on(attribute). def on_base on(:base) end @@ -131,15 +131,15 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.each{|attr,msg| puts "#{attr} - #{msg}" } # => - # name - is too short (minimum is 5 characters) - # name - can't be blank - # address - can't be blank + # company.errors.each{|attr,msg| puts "#{attr} - #{msg}" } + # # => name - is too short (minimum is 5 characters) + # # name - can't be blank + # # address - can't be blank def each @errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } } end - # Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned + # Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned # through iteration as "First name can't be empty". # # class Company < ActiveRecord::Base @@ -148,10 +148,10 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.each_full{|msg| puts msg } # => - # Name is too short (minimum is 5 characters) - # Name can't be blank - # Address can't be blank + # company.errors.each_full{|msg| puts msg } + # # => Name is too short (minimum is 5 characters) + # # Name can't be blank + # # Address can't be blank def each_full full_messages.each { |msg| yield msg } end @@ -164,8 +164,8 @@ module ActiveRecord # end # # 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"] + # 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 full_messages = [] @@ -209,13 +209,13 @@ module ActiveRecord # end # # company = Company.create(:address => '123 First St.') - # company.errors.to_xml # => - # - # - # Name is too short (minimum is 5 characters) - # Name can't be blank - # Address can't be blank - # + # company.errors.to_xml + # # => + # # + # # Name is too short (minimum is 5 characters) + # # Name can't be blank + # # Address can't be blank + # # def to_xml(options={}) options[:root] ||= "errors" options[:indent] ||= 2 @@ -261,7 +261,7 @@ module ActiveRecord # person.errors.on "phone_number" # => "has invalid format" # person.errors.each_full { |msg| puts msg } # # => "Last name can't be empty\n" + - # "Phone number has invalid format" + # # "Phone number has invalid format" # # person.attributes = { "last_name" => "Heinemeier", "phone_number" => "555-555" } # person.save # => true (and person is now saved in the database) @@ -300,7 +300,7 @@ module ActiveRecord :odd => 'odd?', :even => 'even?' }.freeze # Adds a validation method or block to the class. This is useful when - # overriding the +validate+ instance method becomes too unwieldly and + # overriding the +validate+ instance method becomes too unwieldy and # you're looking for more descriptive declaration of your validations. # # This can be done with a symbol pointing to a method: -- cgit v1.2.3 From bbab6391366f59189e84d2b8de2a63bea91a9851 Mon Sep 17 00:00:00 2001 From: Nik Wakelin Date: Thu, 17 Jul 2008 02:50:29 +0100 Subject: Set config.active_record.timestamped_migrations = false to have migrations with numeric prefix instead of UTC timestamp. [#446 state:resolved] Signed-off-by: Pratik Naik --- activerecord/CHANGELOG | 2 ++ activerecord/lib/active_record/base.rb | 4 ++++ activerecord/lib/active_record/migration.rb | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) (limited to 'activerecord') diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 95fdd93f65..90be9b700a 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Edge* +* Set config.active_record.timestamped_migrations = false to have migrations with numeric prefix instead of UTC timestamp. #446. [Andrew Stone, Nik Wakelin] + * change_column_default preserves the not-null constraint. #617 [Tarmo Tänav] * Fixed that create database statements would always include "DEFAULT NULL" (Nick Sieger) [#334] diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index a75e1a5b24..4f5d72a0be 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -439,6 +439,10 @@ module ActiveRecord #:nodoc: cattr_accessor :schema_format , :instance_writer => false @@schema_format = :ruby + # Specify whether or not to use timestamps for migration numbers + cattr_accessor :timestamped_migrations , :instance_writer => false + @@timestamped_migrations = true + # Determine whether to store the full constant name including namespace when using STI superclass_delegating_accessor :store_full_sti_class self.store_full_sti_class = false diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index e095b3c766..731a350854 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -238,6 +238,22 @@ module ActiveRecord # lower than the current schema version: when migrating up, those # never-applied "interleaved" migrations will be automatically applied, and # when migrating down, never-applied "interleaved" migrations will be skipped. + # + # == Timestamped Migrations + # + # By default, Rails generates migrations that look like: + # + # 20080717013526_your_migration_name.rb + # + # The prefix is a generation timestamp (in UTC). + # + # If you'd prefer to use numeric prefixes, you can turn timestamped migrations + # off by setting: + # + # config.active_record.timestamped_migrations = false + # + # In environment.rb. + # class Migration @@verbose = true cattr_accessor :verbose -- cgit v1.2.3 From 1e0f94a77c717dd06a86edda97de5a4c4ad919a8 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Thu, 17 Jul 2008 14:45:14 -0700 Subject: Introduce simple internationalization support --- activerecord/test/i18n_coverage | 6 ------ 1 file changed, 6 deletions(-) delete mode 100755 activerecord/test/i18n_coverage (limited to 'activerecord') diff --git a/activerecord/test/i18n_coverage b/activerecord/test/i18n_coverage deleted file mode 100755 index 1589a6c06f..0000000000 --- a/activerecord/test/i18n_coverage +++ /dev/null @@ -1,6 +0,0 @@ -rcov -I connections/native_mysql \ --x cases/helper,config,connection,models \ --i active_record/validations.rb \ -cases/validations_i18n_test.rb \ - -# cases/validations_test.rb \ No newline at end of file -- cgit v1.2.3 From a1fcbd971d681e44de5ea33e6a8470ff8b8144c0 Mon Sep 17 00:00:00 2001 From: Joachim Garth Date: Fri, 27 Jun 2008 20:03:51 +0200 Subject: Make sure association preloading works with full STI class name [#465 state:Resolved] Signed-off-by: Pratik Naik --- .../lib/active_record/association_preload.rb | 2 +- .../eager_load_includes_full_sti_class_test.rb | 36 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb (limited to 'activerecord') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 64888f9110..c7594809b7 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -252,7 +252,7 @@ module ActiveRecord table_name = reflection.klass.quoted_table_name if interface = reflection.options[:as] - conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} IN (?) and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.name.demodulize}'" + conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} IN (?) and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'" else foreign_key = reflection.primary_key_name conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} IN (?)" diff --git a/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb new file mode 100644 index 0000000000..7c470616a5 --- /dev/null +++ b/activerecord/test/cases/associations/eager_load_includes_full_sti_class_test.rb @@ -0,0 +1,36 @@ +require 'cases/helper' +require 'models/post' +require 'models/tagging' + +module Namespaced + class Post < ActiveRecord::Base + set_table_name 'posts' + has_one :tagging, :as => :taggable, :class_name => 'Tagging' + end +end + +class EagerLoadIncludeFullStiClassNamesTest < ActiveRecord::TestCase + + def setup + generate_test_objects + end + + def generate_test_objects + post = Namespaced::Post.create( :title => 'Great stuff', :body => 'This is not', :author_id => 1 ) + tagging = Tagging.create( :taggable => post ) + end + + def test_class_names + old = ActiveRecord::Base.store_full_sti_class + + ActiveRecord::Base.store_full_sti_class = false + post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging ) + assert_nil post.tagging + + ActiveRecord::Base.store_full_sti_class = true + post = Namespaced::Post.find_by_title( 'Great stuff', :include => :tagging ) + assert_equal 'Tagging', post.tagging.class.name + ensure + ActiveRecord::Base.store_full_sti_class = old + end +end -- cgit v1.2.3 From f2059393481ceb632abc7a9d92670e409020d5bd Mon Sep 17 00:00:00 2001 From: Tom Ward Date: Sat, 19 Jul 2008 09:58:09 +0100 Subject: Ensure checked value is a string when validating case-sensitive uniqueness [#361 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/validations.rb | 2 +- activerecord/test/cases/validations_test.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index 3eec1305e4..b957ee3b9e 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -664,7 +664,7 @@ module ActiveRecord # As MySQL/Postgres don't have case sensitive SELECT queries, we try to find duplicate # column in ruby when case sensitive option if configuration[:case_sensitive] && finder_class.columns_hash[attr_name.to_s].text? - found = results.any? { |a| a[attr_name.to_s] == value } + found = results.any? { |a| a[attr_name.to_s] == value.to_s } end if found diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 60b00b3e8f..4b2d28c80b 100755 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -477,6 +477,15 @@ class ValidationsTest < ActiveRecord::TestCase assert_not_equal "has already been taken", t3.errors.on(:title) end + def test_validate_case_sensitive_uniqueness_with_attribute_passed_as_integer + Topic.validates_uniqueness_of(:title, :case_sensitve => true) + t = Topic.create!('title' => 101) + + t2 = Topic.new('title' => 101) + assert !t2.valid? + assert t2.errors.on(:title) + end + def test_validate_uniqueness_with_non_standard_table_names i1 = WarehouseThing.create(:value => 1000) assert !i1.valid?, "i1 should not be valid" -- cgit v1.2.3 From 3fdd1acab61a46ab4823d63ad0bab4879d2bb446 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sat, 19 Jul 2008 11:30:15 -0500 Subject: Dropped SQLite 2 from default test runner --- activerecord/Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/Rakefile b/activerecord/Rakefile index 60b17e02b9..983528aff7 100755 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -30,7 +30,7 @@ desc 'Run mysql, sqlite, and postgresql tests by default' task :default => :test desc 'Run mysql, sqlite, and postgresql tests' -task :test => %w(test_mysql test_sqlite test_sqlite3 test_postgresql) +task :test => %w(test_mysql test_sqlite3 test_postgresql) for adapter in %w( mysql postgresql sqlite sqlite3 firebird db2 oracle sybase openbase frontbase ) Rake::TestTask.new("test_#{adapter}") { |t| -- cgit v1.2.3 From c67713a2fe78d6f2db49b09771841f5022995703 Mon Sep 17 00:00:00 2001 From: Daniel Guettler Date: Mon, 21 Jul 2008 15:21:13 -0400 Subject: Use klass.sti_name to make sure associations take store_full_sti_class into account. [#671 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/associations.rb | 4 ++-- .../cases/associations/has_many_associations_test.rb | 18 ++++++++++++++++++ activerecord/test/models/company.rb | 7 +++++++ 3 files changed, 27 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index fd9a443eb9..d916275ab9 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1884,7 +1884,7 @@ module ActiveRecord jt_sti_extra = " AND %s.%s = %s" % [ connection.quote_table_name(aliased_join_table_name), connection.quote_column_name(through_reflection.active_record.inheritance_column), - through_reflection.klass.quote_value(through_reflection.klass.name.demodulize)] + through_reflection.klass.quote_value(through_reflection.klass.sti_name)] end when :belongs_to first_key = primary_key @@ -1952,7 +1952,7 @@ module ActiveRecord join << %(AND %s.%s = %s ) % [ connection.quote_table_name(aliased_table_name), connection.quote_column_name(klass.inheritance_column), - klass.quote_value(klass.name.demodulize)] unless klass.descends_from_active_record? + klass.quote_value(klass.sti_name)] unless klass.descends_from_active_record? [through_reflection, reflection].each do |ref| join << "AND #{interpolate_sql(sanitize_sql(ref.options[:conditions]))} " if ref && ref.options[:conditions] diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index b9c7ec6377..f8b8b1f96d 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -999,4 +999,22 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert firm.clients.loaded? end + def test_joins_with_namespaced_model_should_use_correct_type + old = ActiveRecord::Base.store_full_sti_class + ActiveRecord::Base.store_full_sti_class = true + + firm = Namespaced::Firm.create({ :name => 'Some Company' }) + firm.clients.create({ :name => 'Some Client' }) + + stats = Namespaced::Firm.find(firm.id, { + :select => "#{Namespaced::Firm.table_name}.*, COUNT(#{Namespaced::Client.table_name}.id) AS num_clients", + :joins => :clients, + :group => "#{Namespaced::Firm.table_name}.id" + }) + assert_equal 1, stats.num_clients.to_i + + ensure + ActiveRecord::Base.store_full_sti_class = old + end + end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index e6aa810146..cd435948a1 100755 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -18,6 +18,13 @@ end module Namespaced class Company < ::Company end + + class Firm < ::Company + has_many :clients, :class_name => 'Namespaced::Client' + end + + class Client < ::Company + end end class Firm < Company -- cgit v1.2.3 From 8b858782fa693e89a47fc3dd5ae38d842ede6d04 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Mon, 21 Jul 2008 22:41:38 -0500 Subject: Ensure adapater specific code is loaded on ActiveRecord::Base.establish_connection --- .../connection_adapters/abstract/connection_specification.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb index 2a8807fb78..07b122efd1 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb @@ -211,6 +211,7 @@ module ActiveRecord clear_active_connection_name @active_connection_name = name @@defined_connections[name] = spec + connection when Symbol, String if configuration = configurations[spec.to_s] establish_connection(configuration) -- cgit v1.2.3 From 93e10f9911fb2a096681ee0a0bc82487a9a06c44 Mon Sep 17 00:00:00 2001 From: Jan De Poorter Date: Wed, 23 Jul 2008 12:50:16 +0200 Subject: Ensure NamedScope#any? uses COUNT query wherever possible. [#680 state:resolved] Signed-off-by: Pratik Naik --- activerecord/lib/active_record/named_scope.rb | 10 +++++++++- activerecord/test/cases/named_scope_test.rb | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 080e3d0f5e..d5a1c5fe08 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -103,7 +103,7 @@ module ActiveRecord attr_reader :proxy_scope, :proxy_options [].methods.each do |m| - unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last|empty?)/ + unless m =~ /(^__|^nil\?|^send|^object_id$|class|extend|find|count|sum|average|maximum|minimum|paginate|first|last|empty?|any?)/ delegate m, :to => :proxy_found end end @@ -140,6 +140,14 @@ module ActiveRecord @found ? @found.empty? : count.zero? end + def any? + if block_given? + proxy_found.any? { |*block_args| yield(*block_args) } + else + !empty? + end + end + protected def proxy_found @found || load_found diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 0c1eb23428..e21ffbbdba 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -184,6 +184,28 @@ class NamedScopeTest < ActiveRecord::TestCase end end + def test_any_should_not_load_results + topics = Topic.base + assert_queries(1) do + topics.expects(:empty?).returns(true) + assert !topics.any? + end + end + + def test_any_should_call_proxy_found_if_using_a_block + topics = Topic.base + assert_queries(1) do + topics.expects(:empty?).never + topics.any? { true } + end + end + + def test_any_should_not_fire_query_if_named_scope_loaded + topics = Topic.base + topics.collect # force load + assert_no_queries { assert topics.any? } + end + def test_should_build_with_proxy_options topic = Topic.approved.build({}) assert topic.approved -- cgit v1.2.3 From e8fc894f66daa7909d1790f2cd145844d256d282 Mon Sep 17 00:00:00 2001 From: George Ogata Date: Wed, 23 Jul 2008 06:38:26 +1000 Subject: Make observers define #after_find in the model only if needed. [#676 state:resolved] Signed-off-by: Michael Koziarski --- activerecord/lib/active_record/observer.rb | 3 +++ activerecord/test/cases/lifecycle_test.rb | 32 ++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb index c96e5f9d51..b35e407cc1 100644 --- a/activerecord/lib/active_record/observer.rb +++ b/activerecord/lib/active_record/observer.rb @@ -189,6 +189,9 @@ module ActiveRecord def add_observer!(klass) klass.add_observer(self) + if respond_to?(:after_find) && !klass.method_defined?(:after_find) + klass.class_eval 'def after_find() end' + end end end end diff --git a/activerecord/test/cases/lifecycle_test.rb b/activerecord/test/cases/lifecycle_test.rb index 3432abee31..ab005c6b00 100755 --- a/activerecord/test/cases/lifecycle_test.rb +++ b/activerecord/test/cases/lifecycle_test.rb @@ -143,12 +143,12 @@ class LifecycleTest < ActiveRecord::TestCase assert_equal developer.name, multi_observer.record.name end - def test_after_find_cannot_be_observed_when_its_not_defined_on_the_model + def test_after_find_can_be_observed_when_its_not_defined_on_the_model observer = MinimalisticObserver.instance assert_equal Minimalistic, MinimalisticObserver.observed_class minimalistic = Minimalistic.find(1) - assert_nil observer.minimalistic + assert_equal minimalistic, observer.minimalistic end def test_after_find_can_be_observed_when_its_defined_on_the_model @@ -159,6 +159,34 @@ class LifecycleTest < ActiveRecord::TestCase assert_equal topic, observer.topic end + def test_after_find_is_not_created_if_its_not_used + # use a fresh class so an observer can't have defined an + # after_find on it + model_class = Class.new(ActiveRecord::Base) + observer_class = Class.new(ActiveRecord::Observer) + observer_class.observe(model_class) + + observer = observer_class.instance + + assert !model_class.method_defined?(:after_find) + end + + def test_after_find_is_not_clobbered_if_it_already_exists + # use a fresh observer class so we can instantiate it (Observer is + # a Singleton) + model_class = Class.new(ActiveRecord::Base) do + def after_find; end + end + original_method = model_class.instance_method(:after_find) + observer_class = Class.new(ActiveRecord::Observer) do + def after_find; end + end + observer_class.observe(model_class) + + observer = observer_class.instance + assert_equal original_method, model_class.instance_method(:after_find) + end + def test_invalid_observer assert_raise(ArgumentError) { Topic.observers = Object.new; Topic.instantiate_observers } end -- cgit v1.2.3 From 490178c93008c6fca20e3e2d6302a28d86aab94d Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 27 Jul 2008 16:06:51 -0500 Subject: Revert "Ensure adapater specific code is loaded on ActiveRecord::Base.establish_connection" This reverts commit 8b858782fa693e89a47fc3dd5ae38d842ede6d04. --- .../connection_adapters/abstract/connection_specification.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb index 07b122efd1..2a8807fb78 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb @@ -211,7 +211,6 @@ module ActiveRecord clear_active_connection_name @active_connection_name = name @@defined_connections[name] = spec - connection when Symbol, String if configuration = configurations[spec.to_s] establish_connection(configuration) -- cgit v1.2.3