validates_uniqueness_of :name, :case_sensitive => false
помогает, но вы должны помнить, что validates_uniqueness_of
это не гарантирует уникальности, если у вас есть несколько серверов / серверных процессов (например, работает Phusion Passenger, несколько Mongrels и т. д.) или многопоточный сервер. Это потому, что вы можете получить такую последовательность событий (порядок важен):
- Процесс A получает запрос на создание нового пользователя с именем 'foo'
- Процесс B делает то же самое
- Процесс A проверяет уникальность 'foo', спрашивая БД, существует ли это имя еще, и БД сообщает, что имя еще не существует.
- Процесс B делает то же самое и получает такой же ответ
- Процесс A отправляет
insert
заявление для новой записи и завершается успешно.
- Если у вас есть ограничение базы данных, требующее уникальности для этого поля, процесс B отправит
insert
инструкцию для новой записи и завершится ошибкой с уродливым серверным исключением, которое возвращается из адаптера SQL. Если у вас нет ограничения базы данных, вставка будет успешной, и теперь у вас есть две строки с именем «foo».
См. Также «Параллелизм и целостность» в validates_uniqueness_of
документации Rails.
Из третьего издания Ruby on Rails :
... несмотря на свое название, validates_uniqueness_of на самом деле не гарантирует, что значения столбца будут уникальными. Все, что он может сделать, - это убедиться, что ни один столбец не имеет того же значения, что и в проверяемой записи во время проверки. Возможно одновременное создание двух записей, каждая с одинаковым значением столбца, который должен быть уникальным, и для обеих записей, прошедших проверку. Самый надежный способ обеспечить уникальность - это ограничение на уровне базы данных ".
См. Также опыт этого программиста с validates_uniqueness_of
.
Один из способов, которым это обычно происходит, - это случайная двойная отправка с веб-страницы при создании новой учетной записи. Это сложно решить, потому что то, что пользователь получит обратно, является второй (уродливой) ошибкой, и это заставит их думать, что их регистрация не удалась, хотя на самом деле это удалось. Лучший способ, который я нашел, - это просто использовать javascript, чтобы попытаться предотвратить двойную отправку.