[Sql] Проверка уникальности нескольких столбцов



Answers

Вы можете использовать validates для проверки uniqueness в одном столбце:

validates :user_id, uniqueness: {scope: :friend_id}

Синтаксис проверки на несколько столбцов аналогичен, но вместо этого вы должны указать массив полей:

validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}

Однако приведенные выше подходы к проверке имеют условие гонки и не могут обеспечить согласованность. Рассмотрим следующий пример:

  1. записи таблицы базы данных должны быть уникальными по n полям;

  2. несколько ( двух или более ) одновременных запросов, обрабатываемых отдельными процессами каждый ( серверы приложений, серверы рабочего стола или все, что вы используете ), доступ к базе данных для вставки одной и той же записи в таблицу;

  3. каждый параллельный процесс проверяет, есть ли запись с теми же n полями;

  4. валидация для каждого запроса успешно передается, и каждый процесс создает запись в таблице с теми же данными.

Чтобы избежать такого поведения, нужно добавить уникальное ограничение для таблицы db. Вы можете установить его с add_index помощника add_index для одного (или нескольких) полей, выполнив следующую миграцию:

class AddUniqueConstraints < ActiveRecord::Migration
  def change
   add_index :table_name, [:field1, ... , :fieldn], unique: true
  end
end

Предостережение : даже после того, как вы установили уникальное ограничение, два или более одновременных запроса будут пытаться записать одни и те же данные в db, но вместо создания повторяющихся записей это ActiveRecord::RecordNotUnique исключение ActiveRecord::RecordNotUnique , которое вы должны обрабатывать отдельно:

begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end 
Question

Есть ли рельсовый способ проверки того, что фактическая запись уникальна, а не только столбец? Например, модель / таблица дружбы не должна иметь несколько одинаковых записей, например:

user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20



Это можно сделать с ограничением базы данных по двум столбцам:

add_index :friendships, [:user_id, :friend_id], unique: true

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

More reading: https://robots.thoughtbot.com/validation-database-constraint-or-both




Links