validates_uniqueness_of :name, :case_sensitive => false
робить трюк, але слід пам’ятати, що validates_uniqueness_of
це не гарантує унікальності, якщо у вас є кілька серверів / серверних процесів (наприклад, запущений Phusion Passenger, кілька монгрелів тощо) або багатопотоковий сервер. Це тому, що ви можете отримати таку послідовність подій (порядок важливий):
- Процес A отримує запит на створення нового користувача з іменем 'foo'
- Процес В робить те саме
- Процес A перевіряє унікальність 'foo', запитуючи БД, чи існує це ім'я ще, а БД каже, що ім'я ще не існує.
- Процес B робить те саме і отримує однакову відповідь
- Процес A подає
insert
заяву для нового запису та успішно виконує
- Якщо у вас є обмеження для бази даних, що вимагає унікальності для цього поля, процес B подасть
insert
виписку для нового запису і не вдасться з некрасивим винятком сервера, який надходить із адаптера SQL. Якщо у вас немає обмеження для бази даних, вставка буде успішною, і тепер у вас є два рядки з назвою 'foo'.
Див. Також "Паралельність та цілісність" у validates_uniqueness_of
документації Rails.
З Ruby on Rails 3rd Edition :
... незважаючи на свою назву, validates_uniqueness_of насправді не гарантує, що значення стовпців будуть унікальними. Все, що він може зробити, це перевірити, що жоден стовпець не має такого значення, як у записі, який перевіряється на момент перевірки. Можна створити два записи одночасно, кожен з однаковим значенням для стовпця, який повинен бути унікальним, і для обох записів пройти перевірку. Найбільш надійний спосіб забезпечити унікальність - це обмеження на рівні бази даних. "
Дивіться також досвід цього програміста з validates_uniqueness_of
.
Одним із способів, як це часто трапляється, є випадкові подвійні подання з веб-сторінки під час створення нового облікового запису. Цю проблему важко вирішити, оскільки те, що користувач отримає назад, є другою (потворною) помилкою, і це змусить їх думати, що їх реєстрація не вдалася, коли насправді це вдалося. Найкращий спосіб, який я знайшов, щоб запобігти цьому, - це просто використовувати javascript, щоб спробувати запобігти подвійному поданню.