Проверить уникальность нескольких столбцов - PullRequest
186 голосов
/ 02 февраля 2011

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

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

Ответы [ 3 ]

316 голосов
/ 02 февраля 2011

Вы можете назначить вызов validates_uniqueness_of следующим образом.

validates_uniqueness_of :user_id, :scope => :friend_id
127 голосов
/ 30 апреля 2015

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

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

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

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

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

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

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

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

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

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

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

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

begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end 
2 голосов
/ 31 августа 2017

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

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

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

Больше чтения: https://robots.thoughtbot.com/validation-database-constraint-or-both

...