diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2006-02-25 23:54:57 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2006-02-25 23:54:57 +0000 |
commit | 272729e0a339d80bc422fcbdfc86dd60e3e4c030 (patch) | |
tree | e160fa18b89007690dee5df405520cb99800587c /activerecord | |
parent | ad9f678d13db438d48d497bf71ccef6856d58a7d (diff) | |
download | rails-272729e0a339d80bc422fcbdfc86dd60e3e4c030.tar.gz rails-272729e0a339d80bc422fcbdfc86dd60e3e4c030.tar.bz2 rails-272729e0a339d80bc422fcbdfc86dd60e3e4c030.zip |
Fixed validates_length_of to work on UTF-8 strings by using characters instead of bytes (closes #3699) [Masao Mutoh]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3654 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/CHANGELOG | 2 | ||||
-rwxr-xr-x | activerecord/lib/active_record/validations.rb | 46 | ||||
-rw-r--r-- | activerecord/test/connections/native_mysql/connection.rb | 1 | ||||
-rwxr-xr-x | activerecord/test/validations_test.rb | 135 |
4 files changed, 163 insertions, 21 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index d894dd9ee3..1bc3af1987 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Fixed validates_length_of to work on UTF-8 strings by using characters instead of bytes #3699 [Masao Mutoh] + * Fixed that reflections would bleed across class boundaries in single-table inheritance setups #3796 [lars@pind.com] * Added calculations: Base.count, Base.average, Base.sum, Base.minimum, Base.maxmium, and the generic Base.calculate. All can be used with :group and :having. Calculations and statitics need no longer require custom SQL. #3958 [Rick Olson]. Examples: diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb index f733620298..950cf54b12 100755 --- a/activerecord/lib/active_record/validations.rb +++ b/activerecord/lib/active_record/validations.rb @@ -439,31 +439,35 @@ module ActiveRecord option_value = options[range_options.first] case option - 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| - if value.nil? or value.size < option_value.begin - record.errors.add(attr, too_short) - elsif value.size > option_value.end - record.errors.add(attr, too_long) + 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| + if value.nil? or value.split(//).size < option_value.begin + record.errors.add(attr, too_short) + elsif value.split(//).size > option_value.end + record.errors.add(attr, too_long) + end end - end - when :is, :minimum, :maximum - raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0 + when :is, :minimum, :maximum + raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0 - # Declare different validations per option. - validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" } - message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long } + # Declare different validations per option. + 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 + message = (options[:message] || options[message_options[option]]) % option_value - validates_each(attrs, options) do |record, attr, value| - record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] - end + validates_each(attrs, options) do |record, attr, value| + if value.kind_of?(String) + record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value] + else + record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value] + end + end end end diff --git a/activerecord/test/connections/native_mysql/connection.rb b/activerecord/test/connections/native_mysql/connection.rb index dea337567b..b665a6b449 100644 --- a/activerecord/test/connections/native_mysql/connection.rb +++ b/activerecord/test/connections/native_mysql/connection.rb @@ -10,6 +10,7 @@ db2 = 'activerecord_unittest2' ActiveRecord::Base.establish_connection( :adapter => "mysql", :username => "rails", + :encoding => "utf8", :database => db1 ) diff --git a/activerecord/test/validations_test.rb b/activerecord/test/validations_test.rb index 811585b203..4356ea7428 100755 --- a/activerecord/test/validations_test.rb +++ b/activerecord/test/validations_test.rb @@ -614,6 +614,141 @@ class ValidationsTest < Test::Unit::TestCase assert_equal "hoo 5", t.errors["title"] end + def kcode_scope(kcode) + orig_kcode = $KCODE + $KCODE = kcode + begin + yield + ensure + $KCODE = orig_kcode + end + end + + def test_validates_length_of_using_minimum_utf8 + kcode_scope('UTF8') do + Topic.validates_length_of :title, :minimum => 5 + + t = Topic.create("title" => "一二三四五", "content" => "whatever") + assert t.valid? + + t.title = "一二三四" + assert !t.valid? + assert t.errors.on(:title) + assert_equal "is too short (min is 5 characters)", t.errors["title"] + end + end + + def test_validates_length_of_using_maximum_utf8 + kcode_scope('UTF8') do + Topic.validates_length_of :title, :maximum => 5 + + t = Topic.create("title" => "一二三四五", "content" => "whatever") + assert t.valid? + + t.title = "一二34五六" + assert !t.valid? + assert t.errors.on(:title) + assert_equal "is too long (max is 5 characters)", t.errors["title"] + end + end + + def test_validates_length_of_using_within_utf8 + kcode_scope('UTF8') do + Topic.validates_length_of(:title, :content, :within => 3..5) + + t = Topic.new("title" => "一二", "content" => "12三四五六七") + assert !t.valid? + assert_equal "is too short (min is 3 characters)", t.errors.on(:title) + assert_equal "is too long (max is 5 characters)", t.errors.on(:content) + t.title = "一二三" + t.content = "12三" + assert t.valid? + end + end + + def test_optionally_validates_length_of_using_within_utf8 + kcode_scope('UTF8') do + Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true + + t = Topic.create('title' => '一二三', 'content' => '一二三四五') + assert t.valid? + + t.title = nil + assert t.valid? + end + end + + def test_optionally_validates_length_of_using_within_on_create_utf8 + kcode_scope('UTF8') do + Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "長すぎます: %d" + + t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever") + assert !t.save + assert t.errors.on(:title) + assert_equal "長すぎます: 10", t.errors[:title] + + t.title = "一二三四五六七八九" + assert t.save + + t.title = "一二3" + assert t.save + + t.content = "一二三四五六七八九十" + assert t.save + + t.content = t.title = "一二三四五六" + assert t.save + end + end + + def test_optionally_validates_length_of_using_within_on_update_utf8 + kcode_scope('UTF8') do + Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "短すぎます: %d" + + t = Topic.create("title" => "一二三4", "content" => "whatever") + assert !t.save + assert t.errors.on(:title) + + t.title = "1二三4" + assert !t.save + assert t.errors.on(:title) + assert_equal "短すぎます: 5", t.errors[:title] + + t.title = "valid" + t.content = "一二三四五六七八九十A" + assert !t.save + assert t.errors.on(:content) + + t.content = "一二345" + assert t.save + end + end + + def test_validates_length_of_using_is_utf8 + kcode_scope('UTF8') do + Topic.validates_length_of :title, :is => 5 + + t = Topic.create("title" => "一二345", "content" => "whatever") + assert t.valid? + + t.title = "一二345六" + assert !t.valid? + assert t.errors.on(:title) + assert_equal "is the wrong length (should be 5 characters)", t.errors["title"] + end + end + + def test_validates_size_of_association_utf8 + kcode_scope('UTF8') do + assert_nothing_raised { Topic.validates_size_of :replies, :minimum => 1 } + t = Topic.new('title' => 'あいうえお', 'content' => 'かきくけこ') + assert !t.save + assert t.errors.on(:replies) + t.replies.create('title' => 'あいうえお', 'content' => 'かきくけこ') + assert t.valid? + end + end + def test_validates_associated_many Topic.validates_associated( :replies ) t = Topic.create("title" => "uhohuhoh", "content" => "whatever") |