Rails «validates_uniqueness_of» Чувствительность к регистру

96

Вот модель (я использую SQLLite3):

class School < ActiveRecord::Base

  validates_uniqueness_of :name

end

Например, после того, как я добавлю «Йель», я не могу добавить «Йель», но могу добавить « Йель» . Как сделать регистр проверки нечувствительным?

РЕДАКТИРОВАТЬ: нашел - проверки Active Record

GeekJock
источник

Ответы:

232

validates_uniqueness_of :name, :case_sensitive => falseпомогает, но вы должны помнить, что validates_uniqueness_ofэто не гарантирует уникальности, если у вас есть несколько серверов / серверных процессов (например, работает Phusion Passenger, несколько Mongrels и т. д.) или многопоточный сервер. Это потому, что вы можете получить такую ​​последовательность событий (порядок важен):

  1. Процесс A получает запрос на создание нового пользователя с именем 'foo'
  2. Процесс B делает то же самое
  3. Процесс A проверяет уникальность 'foo', спрашивая БД, существует ли это имя еще, и БД сообщает, что имя еще не существует.
  4. Процесс B делает то же самое и получает такой же ответ
  5. Процесс A отправляет insertзаявление для новой записи и завершается успешно.
  6. Если у вас есть ограничение базы данных, требующее уникальности для этого поля, процесс B отправит insertинструкцию для новой записи и завершится ошибкой с уродливым серверным исключением, которое возвращается из адаптера SQL. Если у вас нет ограничения базы данных, вставка будет успешной, и теперь у вас есть две строки с именем «foo».

См. Также «Параллелизм и целостность» в validates_uniqueness_ofдокументации Rails.

Из третьего издания Ruby on Rails :

... несмотря на свое название, validates_uniqueness_of на самом деле не гарантирует, что значения столбца будут уникальными. Все, что он может сделать, - это убедиться, что ни один столбец не имеет того же значения, что и в проверяемой записи во время проверки. Возможно одновременное создание двух записей, каждая с одинаковым значением столбца, который должен быть уникальным, и для обеих записей, прошедших проверку. Самый надежный способ обеспечить уникальность - это ограничение на уровне базы данных ".

См. Также опыт этого программиста с validates_uniqueness_of.

Один из способов, которым это обычно происходит, - это случайная двойная отправка с веб-страницы при создании новой учетной записи. Это сложно решить, потому что то, что пользователь получит обратно, является второй (уродливой) ошибкой, и это заставит их думать, что их регистрация не удалась, хотя на самом деле это удалось. Лучший способ, который я нашел, - это просто использовать javascript, чтобы попытаться предотвратить двойную отправку.

Джордан Бро
источник
4
В качестве примечания - вот патч, который я отправил в Rails, чтобы попытаться исправить эту проблему, применив ограничения уровня базы данных
Джордан Бро
Кроме того, существует постоянная проблема «пользователь дважды щелкнул кнопку отправки», но это скорее исправление с использованием: disable_with
Ghoti
78

В рельсах 3 вы можете сделать это в своей модели:

validates :name, :uniqueness => true

или без case_sensitivity

validates :name, :uniqueness => {:case_sensitive => false}
МаксимусДоминус
источник
Это именно то, что я хочу.
Джигар Бхатт
2
Я занимаюсь Rails более 10 лет. Не могу поверить, что только узнал об этом варианте. В Rails всегда есть чему поучиться ... независимо от уровня навыков.
danielricecodes
25

Есть опция, где вы можете указать нечувствительность к регистру

  validates_uniqueness_of :name, :case_sensitive => false
vrish88
источник
2

Есть аналогичный вопрос, но ответ интереснее: https://stackoverflow.com/a/6422771

По сути, using :case_sensitive => falseвыполняет очень неэффективный запрос к базе данных.

Виктор С
источник