diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index bea0fd26da2bf..3ed3a70f2339b 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,10 @@ *2.1.1 (next release)* +* 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. + validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least %d words."), :tokenizer => lambda {|str| str.scan(/\w+/) } + * Always treat integer :limit as byte length. #420 [Tarmo Tänav] * Partial updates don't update lock_version if nothing changed. #426 [Daniel Morrison] diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index c97aafb1261e1..30767a42e70e8 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -480,8 +480,9 @@ def validates_presence_of(*attr_names) # validates_length_of :fax, :in => 7..32, :allow_nil => true # validates_length_of :phone, :in => 7..32, :allow_blank => true # validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name" - # validates_length_of :fav_bra_size, :minimum=>1, :too_short=>"please enter at least %d character" - # validates_length_of :smurf_leader, :is=>4, :message=>"papa is spelled with %d characters... don't play me." + # validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least %d character" + # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with %d characters... don't play me." + # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least %d words."), :tokenizer => lambda {|str| str.scan(/\w+/) } # end # # Configuration options: @@ -492,7 +493,6 @@ def validates_presence_of(*attr_names) # * :in - A synonym(or alias) for :within. # * :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)"). # * :too_short - The error message if the attribute goes under the minimum (default is: "is too short (min is %d characters)"). # * :wrong_length - The error message if using the :is method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)"). @@ -504,12 +504,16 @@ def validates_presence_of(*attr_names) # * :unless - Specifies a method, proc or string to call to determine if the validation should # 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. + # * :tokenizer - Specifies how to split up the attribute string. (e.g. :tokenizer => lambda {|str| str.scan(/\w+/)} to + # count words as in above example.) + # Defaults to lambda{ |value| value.split(//) } which counts individual characters. 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] + :wrong_length => ActiveRecord::Errors.default_error_messages[:wrong_length], + :tokenizer => lambda {|value| value.split(//)} }.merge(DEFAULT_VALIDATION_OPTIONS) options.update(attrs.extract_options!.symbolize_keys) @@ -536,7 +540,7 @@ def validates_length_of(*attrs) too_long = options[:too_long] % option_value.end validates_each(attrs, options) do |record, attr, value| - value = value.split(//) if value.kind_of?(String) + value = options[:tokenizer].call(value) if value.kind_of?(String) if value.nil? or value.size < option_value.begin record.errors.add(attr, too_short) elsif value.size > option_value.end @@ -553,7 +557,7 @@ def validates_length_of(*attrs) 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) + value = options[:tokenizer].call(value) if value.kind_of?(String) record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] end end diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb index 7b71647d259ba..60566cd0645c7 100755 --- a/activerecord/test/cases/validations_test.rb +++ b/activerecord/test/cases/validations_test.rb @@ -1059,6 +1059,18 @@ def test_validates_length_of_using_is_utf8 end end + def test_validates_length_of_with_block + Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least %d words.", + :tokenizer => lambda {|str| str.scan(/\w+/) } + t = Topic.create!(:content => "this content should be long enough") + assert t.valid? + + t.content = "not long enough" + assert !t.valid? + assert t.errors.on(:content) + assert_equal "Your essay must be at least 5 words.", t.errors[:content] + end + def test_validates_size_of_association_utf8 with_kcode('UTF8') do assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 }