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

Changeset 3654

Show
Ignore:
Timestamp:
02/25/06 23:54:57 (3 years ago)
Author:
david
Message:

Fixed validates_length_of to work on UTF-8 strings by using characters instead of bytes (closes #3699) [Masao Mutoh]

Files:

Legend:

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

    r3650 r3654  
    11*SVN* 
     2 
     3* Fixed validates_length_of to work on UTF-8 strings by using characters instead of bytes #3699 [Masao Mutoh] 
    24 
    35* Fixed that reflections would bleed across class boundaries in single-table inheritance setups #3796 [lars@pind.com] 
  • trunk/activerecord/lib/active_record/validations.rb

    r3639 r3654  
    440440 
    441441        case option 
    442         when :within, :in 
    443           raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) 
    444  
    445           too_short = options[:too_short] % option_value.begin 
    446           too_long  = options[:too_long]  % option_value.end 
    447  
    448           validates_each(attrs, options) do |record, attr, value| 
    449             if value.nil? or value.size < option_value.begin 
    450               record.errors.add(attr, too_short) 
    451             elsif value.size > option_value.end 
    452               record.errors.add(attr, too_long) 
     442          when :within, :in 
     443            raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range) 
     444 
     445            too_short = options[:too_short] % option_value.begin 
     446            too_long  = options[:too_long]  % option_value.end 
     447 
     448            validates_each(attrs, options) do |record, attr, value| 
     449              if value.nil? or value.split(//).size < option_value.begin 
     450                record.errors.add(attr, too_short) 
     451              elsif value.split(//).size > option_value.end 
     452                record.errors.add(attr, too_long) 
     453              end 
    453454            end 
    454           end 
    455         when :is, :minimum, :maximum 
    456           raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0 
    457  
    458           # Declare different validations per option. 
    459           validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" } 
    460           message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } 
    461  
    462           message = (options[:message] || options[message_options[option]]) % option_value 
    463  
    464           validates_each(attrs, options) do |record, attr, value| 
    465             record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] 
    466           end 
     455          when :is, :minimum, :maximum 
     456            raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0 
     457 
     458            # Declare different validations per option. 
     459            validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" } 
     460            message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } 
     461 
     462            message = (options[:message] || options[message_options[option]]) % option_value 
     463 
     464            validates_each(attrs, options) do |record, attr, value| 
     465              if value.kind_of?(String) 
     466                record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value] 
     467              else 
     468                record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] 
     469              end 
     470            end 
    467471        end 
    468472      end 
  • trunk/activerecord/test/connections/native_mysql/connection.rb

    r3182 r3654  
    1111  :adapter  => "mysql", 
    1212  :username => "rails", 
     13  :encoding => "utf8", 
    1314  :database => db1 
    1415) 
  • trunk/activerecord/test/validations_test.rb

    r3206 r3654  
    615615  end 
    616616 
     617  def kcode_scope(kcode) 
     618    orig_kcode = $KCODE 
     619    $KCODE = kcode 
     620    begin 
     621      yield 
     622    ensure 
     623      $KCODE = orig_kcode 
     624    end 
     625  end 
     626 
     627  def test_validates_length_of_using_minimum_utf8 
     628    kcode_scope('UTF8') do 
     629      Topic.validates_length_of :title, :minimum => 5 
     630 
     631      t = Topic.create("title" => "䞀二䞉四五", "content" => "whatever") 
     632      assert t.valid? 
     633 
     634      t.title = "䞀二䞉四" 
     635      assert !t.valid? 
     636      assert t.errors.on(:title) 
     637      assert_equal "is too short (min is 5 characters)", t.errors["title"] 
     638    end 
     639  end 
     640 
     641  def test_validates_length_of_using_maximum_utf8 
     642    kcode_scope('UTF8') do 
     643      Topic.validates_length_of :title, :maximum => 5 
     644 
     645      t = Topic.create("title" => "䞀二䞉四五", "content" => "whatever") 
     646      assert t.valid? 
     647       
     648      t.title = "䞀二34五å 
     649­" 
     650      assert !t.valid? 
     651      assert t.errors.on(:title) 
     652      assert_equal "is too long (max is 5 characters)", t.errors["title"] 
     653    end 
     654  end 
     655 
     656  def test_validates_length_of_using_within_utf8 
     657    kcode_scope('UTF8') do 
     658      Topic.validates_length_of(:title, :content, :within => 3..5) 
     659 
     660      t = Topic.new("title" => "䞀二", "content" => "12䞉四五å 
     661­äžƒ") 
     662      assert !t.valid? 
     663      assert_equal "is too short (min is 3 characters)", t.errors.on(:title) 
     664      assert_equal "is too long (max is 5 characters)", t.errors.on(:content) 
     665      t.title = "䞀二䞉" 
     666      t.content  = "12侉" 
     667      assert t.valid? 
     668    end 
     669  end 
     670 
     671  def test_optionally_validates_length_of_using_within_utf8 
     672    kcode_scope('UTF8') do 
     673      Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true 
     674 
     675      t = Topic.create('title' => '䞀二䞉', 'content' => '䞀二䞉四五') 
     676      assert t.valid? 
     677 
     678      t.title = nil 
     679      assert t.valid? 
     680    end 
     681  end 
     682 
     683  def test_optionally_validates_length_of_using_within_on_create_utf8 
     684    kcode_scope('UTF8') do 
     685      Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "長すぎたす: %d" 
     686 
     687      t = Topic.create("title" => "䞀二䞉四五å 
     688­äžƒå 
     689«ä¹åA", "content" => "whatever") 
     690      assert !t.save 
     691      assert t.errors.on(:title) 
     692      assert_equal "長すぎたす: 10", t.errors[:title] 
     693       
     694      t.title = "䞀二䞉四五å 
     695­äžƒå 
     696«ä¹" 
     697      assert t.save 
     698       
     699      t.title = "䞀二3" 
     700      assert t.save 
     701       
     702      t.content = "䞀二䞉四五å 
     703­äžƒå 
     704«ä¹å" 
     705      assert t.save 
     706       
     707      t.content = t.title = "䞀二䞉四五å 
     708­" 
     709      assert t.save 
     710    end 
     711  end 
     712 
     713  def test_optionally_validates_length_of_using_within_on_update_utf8 
     714    kcode_scope('UTF8') do     
     715      Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "短すぎたす: %d" 
     716 
     717      t = Topic.create("title" => "䞀二䞉4", "content" => "whatever") 
     718      assert !t.save 
     719      assert t.errors.on(:title) 
     720       
     721      t.title = "1二䞉4" 
     722      assert !t.save 
     723      assert t.errors.on(:title) 
     724      assert_equal "短すぎたす: 5", t.errors[:title] 
     725       
     726      t.title = "valid" 
     727      t.content = "䞀二䞉四五å 
     728­äžƒå 
     729«ä¹åA" 
     730      assert !t.save 
     731      assert t.errors.on(:content) 
     732       
     733      t.content = "䞀二345" 
     734      assert t.save 
     735    end 
     736  end 
     737 
     738  def test_validates_length_of_using_is_utf8 
     739    kcode_scope('UTF8') do 
     740      Topic.validates_length_of :title, :is => 5 
     741 
     742      t = Topic.create("title" => "䞀二345", "content" => "whatever") 
     743      assert t.valid? 
     744 
     745      t.title = "䞀二345å 
     746­" 
     747      assert !t.valid? 
     748      assert t.errors.on(:title) 
     749      assert_equal "is the wrong length (should be 5 characters)", t.errors["title"] 
     750    end 
     751  end 
     752 
     753  def test_validates_size_of_association_utf8 
     754    kcode_scope('UTF8') do 
     755      assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 } 
     756      t = Topic.new('title' => 'あいうえお', 'content' => 'かきくけこ') 
     757      assert !t.save 
     758      assert t.errors.on(:replies) 
     759      t.replies.create('title' => 'あいうえお', 'content' => 'かきくけこ') 
     760      assert t.valid? 
     761    end 
     762  end 
     763 
    617764  def test_validates_associated_many 
    618765    Topic.validates_associated( :replies )