Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 6850

Show
Ignore:
Timestamp:
05/26/07 00:30:14 (2 years ago)
Author:
bitsweat
Message:

validates_numericality_of takes :greater_than, :greater_than_or_equal_to, :equal_to, :less_than, :less_than_or_equal_to, :odd, and :even options. Closes #3952.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activerecord/CHANGELOG

    r6848 r6850  
    11*SVN* 
     2 
     3* validates_numericality_of takes :greater_than, :greater_than_or_equal_to, :equal_to, :less_than, :less_than_or_equal_to, :odd, and :even options.  #3952 [Bob Silva, Dan Kubb, Josh Peek] 
    24 
    35* MySQL: create_database takes :charset and :collation options. Charset defaults to utf8.  #8448 [matt] 
  • trunk/activerecord/lib/active_record/validations.rb

    r6687 r6850  
    3636      :wrong_length => "is the wrong length (should be %d characters)", 
    3737      :taken => "has already been taken", 
    38       :not_a_number => "is not a number" 
     38      :not_a_number => "is not a number", 
     39      :greater_than => "must be greater than %d", 
     40      :greater_than_or_equal_to => "must be greater than or equal to %d", 
     41      :equal_to => "must be equal to %d", 
     42      :less_than => "must be less than %d", 
     43      :less_than_or_equal_to => "must be less than or equal to %d", 
     44      :odd => "must be odd", 
     45      :even => "must be even" 
    3946    } 
    4047 
     
    299306 
    300307      ALL_RANGE_OPTIONS = [ :is, :within, :in, :minimum, :maximum ].freeze 
     308      ALL_NUMERICALITY_CHECKS = { :greater_than => '>', :greater_than_or_equal_to => '>=', 
     309                                  :equal_to => '==', :less_than => '<', :less_than_or_equal_to => '<=', 
     310                                  :odd => 'odd?', :even => 'even?' }.freeze 
     311 
    301312 
    302313      def validate(*methods, &block) 
     
    752763      # * <tt>only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is false) 
    753764      # * <tt>allow_nil</tt> Skip validation if attribute is nil (default is false). Notice that for fixnum and float columns empty strings are converted to nil 
     765      # * <tt>greater_than</tt> Specifies the value must be greater than the supplied value 
     766      # * <tt>greater_than_or_equal_to</tt> Specifies the value must be greater than or equal the supplied value 
     767      # * <tt>equal_to</tt> Specifies the value must be equal to the supplied value 
     768      # * <tt>less_than</tt> Specifies the value must be less than the supplied value 
     769      # * <tt>less_than_or_equal_to</tt> Specifies the value must be less than or equal the supplied value 
     770      # * <tt>odd</tt> Specifies the value must be an odd number 
     771      # * <tt>even</tt> Specifies the value must be an even number 
    754772      # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should 
    755773      # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }).  The 
    756774      # method, proc or string should return or evaluate to a true or false value. 
    757775      def validates_numericality_of(*attr_names) 
    758         configuration = { :message => ActiveRecord::Errors.default_error_messages[:not_a_number], :on => :save, 
    759                            :only_integer => false, :allow_nil => false } 
     776        configuration = { :on => :save, :only_integer => false, :allow_nil => false } 
    760777        configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) 
    761778 
    762         if configuration[:only_integer] 
    763           validates_each(attr_names,configuration) do |record, attr_name,value| 
    764             record.errors.add(attr_name, configuration[:message]) unless record.send("#{attr_name}_before_type_cast").to_s =~ /\A[+-]?\d+\Z/ 
    765           end 
    766         else 
    767           validates_each(attr_names,configuration) do |record, attr_name,value| 
    768            next if configuration[:allow_nil] and record.send("#{attr_name}_before_type_cast").nil? 
    769             begin 
    770               Kernel.Float(record.send("#{attr_name}_before_type_cast").to_s) 
     779        numericality_options = ALL_NUMERICALITY_CHECKS.keys & configuration.keys 
     780 
     781        (numericality_options - [ :odd, :even ]).each do |option| 
     782          raise ArgumentError, ":#{option} must be a number" unless configuration[option].is_a?(Numeric) 
     783        end 
     784 
     785        validates_each(attr_names,configuration) do |record, attr_name, value| 
     786          raw_value = record.send("#{attr_name}_before_type_cast") || value 
     787 
     788          next if configuration[:allow_nil] and raw_value.nil? 
     789 
     790          if configuration[:only_integer] 
     791            unless raw_value.to_s =~ /\A[+-]?\d+\Z/ 
     792              record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number]) 
     793              next 
     794            end 
     795            raw_value = raw_value.to_i 
     796          else 
     797           begin 
     798              raw_value = Kernel.Float(raw_value.to_s) 
    771799            rescue ArgumentError, TypeError 
    772               record.errors.add(attr_name, configuration[:message]) 
     800              record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number]) 
     801              next 
    773802            end 
    774803          end 
    775         end 
    776       end 
    777  
     804 
     805          numericality_options.each do |option| 
     806            case option 
     807              when :odd, :even 
     808                record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[option]) unless raw_value.to_i.method(ALL_NUMERICALITY_CHECKS[option])[] 
     809              else 
     810                record.errors.add(attr_name, configuration[:message] || (ActiveRecord::Errors.default_error_messages[option] % configuration[option])) unless raw_value.method(ALL_NUMERICALITY_CHECKS[option])[configuration[option]] 
     811            end 
     812          end 
     813        end 
     814      end 
    778815 
    779816      # Creates an object just like Base.create but calls save! instead of save 
  • trunk/activerecord/test/validations_test.rb

    r5684 r6850  
    445445  end 
    446446 
     447  def test_numericality_with_getter_method 
     448    Developer.validates_numericality_of( :salary ) 
     449    developer = Developer.new("name" => "michael", "salary" => nil) 
     450    developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end") 
     451    assert developer.valid? 
     452  end 
     453 
    447454  def test_numericality_with_allow_nil_and_getter_method 
    448455    Developer.validates_numericality_of( :salary, :allow_nil => true) 
     
    11201127  end 
    11211128 
     1129  def test_validates_numericality_with_greater_than 
     1130    Topic.validates_numericality_of :approved, :greater_than => 10 
     1131 
     1132    invalid!([-10, 10], 'must be greater than 10') 
     1133    valid!([11]) 
     1134  end 
     1135 
     1136  def test_validates_numericality_with_greater_than_or_equal 
     1137    Topic.validates_numericality_of :approved, :greater_than_or_equal_to => 10 
     1138 
     1139    invalid!([-9, 9], 'must be greater than or equal to 10') 
     1140    valid!([10]) 
     1141  end 
     1142 
     1143  def test_validates_numericality_with_equal_to 
     1144    Topic.validates_numericality_of :approved, :equal_to => 10 
     1145 
     1146    invalid!([-10, 11], 'must be equal to 10') 
     1147    valid!([10]) 
     1148  end 
     1149 
     1150  def test_validates_numericality_with_less_than 
     1151    Topic.validates_numericality_of :approved, :less_than => 10 
     1152 
     1153    invalid!([10], 'must be less than 10') 
     1154    valid!([-9, 9]) 
     1155  end 
     1156 
     1157  def test_validates_numericality_with_less_than_or_equal_to 
     1158    Topic.validates_numericality_of :approved, :less_than_or_equal_to => 10 
     1159 
     1160    invalid!([11], 'must be less than or equal to 10') 
     1161    valid!([-10, 10]) 
     1162  end 
     1163 
     1164  def test_validates_numericality_with_odd 
     1165    Topic.validates_numericality_of :approved, :odd => true 
     1166 
     1167    invalid!([-2, 2], 'must be odd') 
     1168    valid!([-1, 1]) 
     1169  end 
     1170 
     1171  def test_validates_numericality_with_even 
     1172    Topic.validates_numericality_of :approved, :even => true 
     1173 
     1174    invalid!([-1, 1], 'must be even') 
     1175    valid!([-2, 2]) 
     1176  end 
     1177 
     1178  def test_validates_numericality_with_greater_than_less_than_and_even 
     1179    Topic.validates_numericality_of :approved, :greater_than => 1, :less_than => 4, :even => true 
     1180 
     1181    invalid!([1, 3, 4]) 
     1182    valid!([2]) 
     1183  end 
     1184 
    11221185  private 
    1123     def invalid!(values
     1186    def invalid!(values, error=nil
    11241187      with_each_topic_approved_value(values) do |topic, value| 
    11251188        assert !topic.valid?, "#{value.inspect} not rejected as a number" 
    11261189        assert topic.errors.on(:approved) 
     1190        assert_equal error, topic.errors.on(:approved) if error 
    11271191      end 
    11281192    end