Skip to content

Commit 3daf2c7

Browse files
kamiporafaelfranca
authored andcommitted
MySQL: Uniqueness validator now respects default database collation
No longer enforce case sensitive comparison by default.
1 parent bc28e37 commit 3daf2c7

File tree

7 files changed

+33
-67
lines changed

7 files changed

+33
-67
lines changed

activerecord/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
* MySQL: Uniqueness validator now respects default database collation,
2+
no longer enforce case sensitive comparison by default.
3+
4+
*Ryuta Kamizono*
5+
16
* Remove deprecated methods from `ActiveRecord::ConnectionAdapters::DatabaseLimits`.
27

38
`column_name_length`

activerecord/lib/active_record/connection_adapters/abstract_adapter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ def raw_connection
529529
@connection
530530
end
531531

532-
def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
532+
def default_uniqueness_comparison(attribute, value) # :nodoc:
533533
attribute.eq(value)
534534
end
535535

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -502,21 +502,6 @@ def primary_keys(table_name) # :nodoc:
502502
SQL
503503
end
504504

505-
def default_uniqueness_comparison(attribute, value, klass) # :nodoc:
506-
column = column_for_attribute(attribute)
507-
508-
if column.collation && !column.case_sensitive? && !value.nil?
509-
ActiveSupport::Deprecation.warn(<<~MSG.squish)
510-
Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1.
511-
To continue case sensitive comparison on the :#{attribute.name} attribute in #{klass} model,
512-
pass `case_sensitive: true` option explicitly to the uniqueness validator.
513-
MSG
514-
attribute.eq(Arel::Nodes::Bin.new(value))
515-
else
516-
super
517-
end
518-
end
519-
520505
def case_sensitive_comparison(attribute, value) # :nodoc:
521506
column = column_for_attribute(attribute)
522507

activerecord/lib/active_record/validations/uniqueness.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def build_relation(klass, attribute, value)
7070
return relation.none! if bind.unboundable?
7171

7272
if !options.key?(:case_sensitive) || bind.nil?
73-
klass.connection.default_uniqueness_comparison(attr, bind, klass)
73+
klass.connection.default_uniqueness_comparison(attr, bind)
7474
elsif options[:case_sensitive]
7575
klass.connection.case_sensitive_comparison(attr, bind)
7676
else

activerecord/test/cases/validations/uniqueness_validation_test.rb

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -333,49 +333,29 @@ def test_validate_case_insensitive_uniqueness_with_special_sql_like_chars
333333
assert t3.save, "Should save t3 as unique"
334334
end
335335

336-
if current_adapter?(:Mysql2Adapter)
337-
def test_deprecate_validate_uniqueness_mismatched_collation
338-
Topic.validates_uniqueness_of(:author_email_address)
339-
340-
topic1 = Topic.new(author_email_address: "david@loudthinking.com")
341-
topic2 = Topic.new(author_email_address: "David@loudthinking.com")
342-
343-
assert_equal 1, Topic.where(author_email_address: "david@loudthinking.com").count
344-
345-
assert_deprecated do
346-
assert_not topic1.valid?
347-
assert_not topic1.save
348-
assert topic2.valid?
349-
assert topic2.save
350-
end
351-
352-
assert_equal 2, Topic.where(author_email_address: "david@loudthinking.com").count
353-
assert_equal 2, Topic.where(author_email_address: "David@loudthinking.com").count
354-
end
355-
end
356-
357-
def test_validate_case_sensitive_uniqueness_by_default
336+
def test_validate_uniqueness_by_default_database_collation
358337
Topic.validates_uniqueness_of(:author_email_address)
359338

360339
topic1 = Topic.new(author_email_address: "david@loudthinking.com")
361340
topic2 = Topic.new(author_email_address: "David@loudthinking.com")
362341

363342
assert_equal 1, Topic.where(author_email_address: "david@loudthinking.com").count
364343

365-
ActiveSupport::Deprecation.silence do
366-
assert_not topic1.valid?
367-
assert_not topic1.save
368-
assert topic2.valid?
369-
assert topic2.save
370-
end
344+
assert_not topic1.valid?
345+
assert_not topic1.save
371346

372347
if current_adapter?(:Mysql2Adapter)
373-
assert_equal 2, Topic.where(author_email_address: "david@loudthinking.com").count
374-
assert_equal 2, Topic.where(author_email_address: "David@loudthinking.com").count
348+
# Case insensitive collation (utf8mb4_0900_ai_ci) by default.
349+
# Should not allow "David" if "david" exists.
350+
assert_not topic2.valid?
351+
assert_not topic2.save
375352
else
376-
assert_equal 1, Topic.where(author_email_address: "david@loudthinking.com").count
377-
assert_equal 1, Topic.where(author_email_address: "David@loudthinking.com").count
353+
assert topic2.valid?
354+
assert topic2.save
378355
end
356+
357+
assert_equal 1, Topic.where(author_email_address: "david@loudthinking.com").count
358+
assert_equal 1, Topic.where(author_email_address: "David@loudthinking.com").count
379359
end
380360

381361
def test_validate_case_sensitive_uniqueness

activerecord/test/schema/schema.rb

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,6 @@
88
# #
99
# ------------------------------------------------------------------- #
1010

11-
case_sensitive_options =
12-
if current_adapter?(:Mysql2Adapter)
13-
{ collation: "utf8mb4_bin" }
14-
else
15-
{}
16-
end
17-
1811
create_table :accounts, force: true do |t|
1912
t.references :firm, index: false
2013
t.string :firm_name
@@ -115,7 +108,7 @@
115108
t.column :font_size, :integer, **default_zero
116109
t.column :difficulty, :integer, **default_zero
117110
t.column :cover, :string, default: "hard"
118-
t.string :isbn, **case_sensitive_options
111+
t.string :isbn
119112
t.string :external_id
120113
t.datetime :published_on
121114
t.boolean :boolean_status
@@ -290,7 +283,7 @@
290283
end
291284

292285
create_table :dashboards, force: true, id: false do |t|
293-
t.string :dashboard_id, **case_sensitive_options
286+
t.string :dashboard_id
294287
t.string :name
295288
end
296289

@@ -403,7 +396,7 @@
403396
end
404397

405398
create_table :essays, force: true do |t|
406-
t.string :name, **case_sensitive_options
399+
t.string :name
407400
t.string :writer_id
408401
t.string :writer_type
409402
t.string :category_id
@@ -412,7 +405,7 @@
412405
end
413406

414407
create_table :events, force: true do |t|
415-
t.string :title, limit: 5, **case_sensitive_options
408+
t.string :title, limit: 5
416409
end
417410

418411
create_table :eyes, force: true do |t|
@@ -454,16 +447,16 @@
454447
end
455448

456449
create_table :guids, force: true do |t|
457-
t.column :key, :string, **case_sensitive_options
450+
t.column :key, :string
458451
end
459452

460453
create_table :guitars, force: true do |t|
461454
t.string :color
462455
end
463456

464457
create_table :inept_wizards, force: true do |t|
465-
t.column :name, :string, null: false, **case_sensitive_options
466-
t.column :city, :string, null: false, **case_sensitive_options
458+
t.column :name, :string, null: false
459+
t.column :city, :string, null: false
467460
t.column :type, :string
468461
end
469462

@@ -988,8 +981,8 @@
988981
end
989982

990983
create_table :topics, force: true do |t|
991-
t.string :title, limit: 250, **case_sensitive_options
992-
t.string :author_name, **case_sensitive_options
984+
t.string :title, limit: 250
985+
t.string :author_name
993986
t.string :author_email_address
994987
if supports_datetime_with_precision?
995988
t.datetime :written_on, precision: 6
@@ -1001,10 +994,10 @@
1001994
# use VARCHAR2(4000) instead of CLOB datatype as CLOB data type has many limitations in
1002995
# Oracle SELECT WHERE clause which causes many unit test failures
1003996
if current_adapter?(:OracleAdapter)
1004-
t.string :content, limit: 4000, **case_sensitive_options
997+
t.string :content, limit: 4000
1005998
t.string :important, limit: 4000
1006999
else
1007-
t.text :content, **case_sensitive_options
1000+
t.text :content
10081001
t.text :important
10091002
end
10101003
t.boolean :approved, default: true

guides/source/6_1_release_notes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ Please refer to the [Changelog][active-record] for detailed changes.
149149

150150
### Removals
151151

152+
* MySQL: Uniqueness validator now respects default database collation,
153+
no longer enforce case sensitive comparison by default.
154+
152155
* Remove deprecated methods from `ActiveRecord::ConnectionAdapters::DatabaseLimits`.
153156

154157
`column_name_length`

0 commit comments

Comments
 (0)