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