を使用validates
してuniqueness
、1つの列を検証できます。
validates :user_id, uniqueness: {scope: :friend_id}
複数の列の検証の構文は似ていますが、代わりにフィールドの配列を提供する必要があります。
validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}
ただし、上記の検証アプローチには競合状態があり、一貫性を保証できません。次の例について考えてみます。
データベーステーブルレコードは、nフィールドで一意であると想定されています。
複数(2つ以上)の同時要求は、それぞれ個別のプロセス(アプリケーションサーバー、バックグラウンドワーカーサーバー、または使用しているもの)によって処理され、データベースにアクセスして同じレコードをテーブルに挿入します。
各プロセスは並行して、同じnフィールドのレコードがあるかどうかを検証します。
各リクエストの検証は正常に渡され、各プロセスは同じデータを持つテーブルにレコードを作成します。
この種の動作を回避するには、一意の制約をdbテーブルに追加する必要があります。add_index
次の移行を実行して、1つ(または複数)のフィールドにヘルパーを設定できます。
class AddUniqueConstraints < ActiveRecord::Migration
def change
add_index :table_name, [:field1, ... , :fieldn], unique: true
end
end
警告:一意の制約を設定した後でも、2つ以上の同時リクエストが同じデータをデータベースに書き込もうとしますが、重複したレコードを作成する代わりに、ActiveRecord::RecordNotUnique
例外が発生します。これは個別に処理する必要があります。
begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end