From 90a58003614541f499eb2800095f2fdfa500f83e Mon Sep 17 00:00:00 2001 From: Jose Fernandez Date: Fri, 22 Aug 2008 16:58:52 -0500 Subject: [PATCH] validates_length_of will now work correctly on numbers unless the :byte_size option is set to true (defaults to false, only works on Fixnum's and Bignum's). --- activerecord/lib/active_record/validations.rb | 20 ++++++++--- activerecord/test/cases/validations_test.rb | 42 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index b7e6394..3c8ea2d 100644 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -499,6 +499,7 @@ module ActiveRecord # * :is - The exact size of the attribute. # * :within - A range specifying the minimum and maximum size of the attribute. # * :in - A synonym(or alias) for :within. + # * :byte_size - A boolean specifying if the attribute's byte size should be used. Only works for Fixnum's and Bignum's, defaults to false. # * :allow_nil - Attribute may be +nil+; skip validation. # * :allow_blank - Attribute may be blank; skip validation. # * :too_long - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %d characters)"). @@ -518,7 +519,8 @@ module ActiveRecord def validates_length_of(*attrs) # Merge given options with defaults. options = { - :tokenizer => lambda {|value| value.split(//)} + :tokenizer => lambda {|value| value.split(//)}, + :byte_size => false }.merge(DEFAULT_VALIDATION_OPTIONS) options.update(attrs.extract_options!.symbolize_keys) @@ -542,11 +544,14 @@ module ActiveRecord raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) validates_each(attrs, options) do |record, attr, value| - value = options[:tokenizer].call(value) if value.kind_of?(String) - if value.nil? or value.size < option_value.begin + value = options[:tokenizer].call(value) if value.kind_of?(String) + size = value.to_s.size if value.is_a?(Numeric) && (value.is_a?(Float) || !options[:byte_size]) + size ||= value.nil? ? nil : value.size + + if value.nil? || size < option_value.begin 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 + elsif size > option_value.end message = record.errors.generate_message(attr, :too_long, :default => options[:too_long], :count => option_value.end) record.errors.add(attr, message) end @@ -559,8 +564,11 @@ module ActiveRecord message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } validates_each(attrs, options) do |record, attr, value| - value = options[:tokenizer].call(value) if value.kind_of?(String) - unless !value.nil? and value.size.method(validity_checks[option])[option_value] + value = options[:tokenizer].call(value) if value.kind_of?(String) + size = value.to_s.size if value.is_a?(Numeric) && (value.is_a?(Float) || !options[:byte_size]) + size ||= value.nil? ? nil : value.size + + unless !value.nil? && 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) diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 4b2d28c..1509a43 100644 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -860,6 +860,48 @@ class ValidationsTest < ActiveRecord::TestCase Topic.validates_length_of :title, :maximum => bigmax end end + + def test_validates_length_of_using_a_fixnum + Topic.validates_length_of :title, :is => 5 + + t = Topic.create("title" => 12345) + assert t.valid? + end + + def test_validates_length_of_using_a_bignum + Topic.validates_length_of :title, :is => 10 + + t = Topic.create("title" => 1234567890) + assert t.valid? + end + + def test_validates_length_of_using_a_float + Topic.validates_length_of :title, :is => 6 + + t = Topic.create("title" => 1234.5) + assert t.valid? + end + + def test_validates_length_of_using_a_fixnum_and_byte_size + Topic.validates_length_of :title, :is => 4, :byte_size => true + + t = Topic.create("title" => 12345) + assert t.valid? + end + + def test_validates_length_of_using_a_bignum_and_byte_size + Topic.validates_length_of :title, :is => 4, :byte_size => true + + t = Topic.create("title" => 1234567890) + assert t.valid? + end + + def test_validates_length_of_using_a_float_and_byte_size + Topic.validates_length_of :title, :is => 10, :byte_size => true + + t = Topic.create("title" => 12345678.9) + assert t.valid? + end def test_validates_length_with_globally_modified_error_message ActiveSupport::Deprecation.silence do -- 1.6.0.1