Rails: проверка уникальной комбинации из 3 столбцов
Привет, я не хочу проверять уникальную комбинацию из 3 столбцов в моей таблице.
Скажем, у меня есть таблица под названием cars со значениями: brand,: model_name и: fuel_type.
То, что я тогда хочу, это проверить, уникальна ли запись на основе их комбинации. Пример:
brand model_name fuel_type
Audi A4 Gas
Audi A4 Diesel
Audi A6 Gas
Все должны быть действительными. Но другой рекорд с "Audi, A6, Gas" НЕ должен быть действительным.
Я знаю эту проверку, но я сомневаюсь, что она действительно делает то, что я хочу.
validates_uniqueness_of :brand, :scope => {:model_name, :fuel_type}
Ответы
Ответ 1
В фрагменте кода есть синтаксическая ошибка. Правильная проверка:
validates_uniqueness_of :car_model_name, :scope => [:brand_id, :fuel_type_id]
или даже короче в рубине 1.9.x:
validates_uniqueness_of :car_model_name, scope: [:brand_id, :fuel_type_id]
с рельсами 4 вы можете использовать:
validates :car_model_name, uniqueness: { scope: [:brand_id, :fuel_type_id] }
с рельсами 5 вы можете использовать
validates_uniqueness_of :car_model_name, scope: %i[brand_id fuel_type_id]
Ответ 2
В зависимости от ваших потребностей вы также можете добавить ограничение (как часть миграции создания таблицы или как отдельную) вместо проверки модели:
add_index :the_table_name, [:brand, :model_name, :fuel_type], :unique => true
Добавление уникального ограничения на уровень базы данных имеет смысл, если несколько соединений с базой данных выполняют операции записи одновременно.
Ответ 3
Я бы сделал так:
validates_uniqueness_of :model_name, :scope => {:brand_id, :fuel_type_id}
потому что это имеет для меня больше смысла:
- не следует дублировать "названия моделей" для комбинации "бренд" и "тип топлива", vs
- не следует дублировать "бренды" для комбинации "название модели" и "тип топлива".
но это субъективное мнение.
Конечно, если бренд и fuel_type являются отношениями с другими моделями (если нет, то просто снимите "_id" часть). С проверкой уникальности вы не можете проверить столбцы не-db, поэтому вам нужно проверить внешние ключи в модели.
Вам нужно определить, какой атрибут проверен - вы не проверяете все сразу, если хотите, вам нужно создать отдельную проверку для каждого атрибута, поэтому, когда пользователь совершает ошибку и пытается создать дублируемую запись, вы показываете его ошибки в форме возле недопустимого поля.
Ответ 4
To Rails 4 правильный код с новым хеш-шаблоном
validates :column_name, uniqueness: {scope: [:brand_id, :fuel_type_id]}
Ответ 5
Использование этого метода проверки в сочетании с ActiveRecord::Validations#save
не гарантирует отсутствие повторных вводов записей, поскольку проверки уникальности на уровне приложения по своей природе подвержены условиям гонки.
Это может произойти, если вы используете транзакции с уровнем "сериализации". Лучший способ обойти эту проблему - добавить уникальный индекс в таблицу базы данных, используя ActiveRecord::ConnectionAdapters::SchemaStatements#add_index
. В редком случае, когда возникает условие гонки, база данных гарантирует уникальность поля.