Найдите SQL, выполняющий validates_uniqueness_of
, в своем журнале разработки, и если вы видите что-то вроде WHERE (email = BINARY 'foo@example.com')
, попробуйте создать пользователя с FOO@EXAMPLE.COM
, и теперь вы можете воспроизвести исключение дублирования на уровне базы данных.
Чтобы исправить это, введите следующий код в config/initializers/patches.rb
:
class ActiveRecord::ConnectionAdapters::Mysql2Adapter
def case_sensitive_equality_operator
"="
end
end
Обратите внимание, что Mysql2Adapter
должно быть MysqlAdapter
, если вы находитесь на Rails 2.
На сторонеобратите внимание, это давняя ошибка в Rails IMO - обработка чувствительности к регистру на уровне Ruby вообще не имеет смысла.Если вам нужен поиск с учетом регистра, у вас должно быть сопоставление столбцов utf8_bin
.Если вам нужен поиск без учета регистра, у вас должно быть сопоставление столбцов utf8_general_ci
.Применение функции BINARY
в предложении where отключит использование индекса, а validates_uniqueness_of
вызывает полное сканирование таблицы каждый раз, когда вы пытаетесь создать / обновить запись.Если у вас есть миллионы записей, вы полностью испорчены.Патч выше исправит это тоже - на самом деле, это была моя первоначальная мотивация для создания этого патча.
Если вы согласны, пожалуйста, +1 к https://github.com/rails/rails/issues/1399:)