From 811a4fa8eb6ceea841e61e8ac05747ffb69595ae Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Wed, 27 Jan 2016 10:47:15 +0900 Subject: [PATCH] Avoid a string value truncation in uniqueness validation In MySQL, PostgreSQL, Oracle and SQLServer, a value over the limit cannot be inserted or updated (See #23522). In SQLite3, a value is inserted or updated regardless of the limit. We should avoid a string value truncation in uniqueness validation. --- .../active_record/validations/uniqueness.rb | 3 -- .../validations/uniqueness_validation_test.rb | 32 +++++++++++++------ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index f0aa4521b5..6343de5914 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -69,9 +69,6 @@ module ActiveRecord cast_type = klass.type_for_attribute(attribute_name) value = cast_type.serialize(value) value = klass.connection.type_cast(value) - if value.is_a?(String) && column.limit - value = value.to_s[0, column.limit] - end comparison = if !options[:case_sensitive] && !value.nil? # will use SQL LOWER function before comparison, unless it detects a case insensitive collation diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb index e601c53dbf..6264ec15d0 100644 --- a/activerecord/test/cases/validations/uniqueness_validation_test.rb +++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb @@ -336,19 +336,31 @@ class UniquenessValidationTest < ActiveRecord::TestCase end def test_validate_uniqueness_with_limit - # Event.title is limited to 5 characters - e1 = Event.create(:title => "abcde") - assert e1.valid?, "Could not create an event with a unique, 5 character title" - e2 = Event.create(:title => "abcdefgh") - assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique" + if current_adapter?(:SQLite3Adapter) + # Event.title has limit 5, but does not affected in SQLite. + e1 = Event.create(title: "abcdefgh") + assert e1.valid?, "Could not create an event with a unique 8 characters title" + e2 = Event.create(title: "abcdefgh") + assert !e2.valid?, "Created an event whose title is not unique" + elsif current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter, :SQLServerAdapter) + assert_raise(ActiveRecord::StatementInvalid) do + Event.create(title: "abcdefgh") + end + end end def test_validate_uniqueness_with_limit_and_utf8 - # Event.title is limited to 5 characters - e1 = Event.create(:title => "一二三四五") - assert e1.valid?, "Could not create an event with a unique, 5 character title" - e2 = Event.create(:title => "一二三四五六七八") - assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique" + if current_adapter?(:SQLite3Adapter) + # Event.title has limit 5, but does not affected in SQLite. + e1 = Event.create(title: "一二三四五六七八") + assert e1.valid?, "Could not create an event with a unique 8 characters title" + e2 = Event.create(title: "一二三四五六七八") + assert !e2.valid?, "Created an event whose title is not unique" + elsif current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter, :SQLServerAdapter) + assert_raise(ActiveRecord::StatementInvalid) do + Event.create(title: "一二三四五六七八") + end + end end def test_validate_straight_inheritance_uniqueness