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