一意のインデックスとvalidates_uniqueness_of
の違いは次のとおりです。これは、ActiveRecordがdbで生成された一意の制約違反のエラーを識別できるようにするパッチです。たとえば、validates_uniqueness_ofを宣言せずに次の作業を行います:
create_table "users" do |t|
t.string "email", null: false
end
add_index "users", ["email"], unique: true
class User < ActiveRecord::Base
end
User.create!(email: '[email protected]')
u = User.create(email: '[email protected]')
u.errors[:email]
=> "has already been taken"
利点は、スピード、使いやすさ、完全性です-
速度
このアプローチでは、保存時に一意性をチェックするためにdbルックアップを実行する必要はありません(インデックスが欠落していると非常に遅くなることがあります- https://rails.lighthouseapp.com/projects/8994/tickets/2503-validate .. 。 )。一意性の検証に本当に関心がある場合は、とにかくデータベース制約を使用する必要があります。これにより、データベースは何があっても一意性を検証し、このアプローチによって余分なクエリが削除されます。インデックスを2回チェックすることは、DBにとって問題ではありません(2回目にキャッシュされます)が、アプリケーションからのDBラウンドトリップを節約することは大きなメリットです。
使いやすさ
とにかく真の一意性のためにdb制約が必要であることを考えると、このアプローチでは、db制約が設定されると、すべてが自動的に実行されます。必要に応じて、validates_uniqueness_ofを引き続き使用できます。
完全性
validates_uniqueness_ofは常にちょっとしたハックでした。競合状態を適切に処理できず、多少冗長なエラー処理ロジックを使用して処理する必要のある例外が発生します。 ( http://api.rubyonrailsの「同時実行性と整合性」セクションを参照してください。 .org / classes / ActiveRecord / Validations / ClassMe ... )
validates_uniqueness_of 値の一意性を保証するには不十分です。この理由は、本番環境では、複数のワーカープロセスが競合状態を引き起こす可能性があるためです。
-
2つの同時リクエストが同じ名前のユーザーを作成しようとします(ユーザー名を一意にする必要があります)
-
リクエストはサーバー上で2つのワーカープロセスによって受け入れられ、2つのワーカープロセスが並行して処理します
-
どちらのリクエストもusersテーブルをスキャンして、名前が使用可能であることを確認します
-
どちらのリクエストも検証に合格し、一見利用可能な名前のユーザーを作成します
より明確に理解するには、これを確認してください
列に一意のインデックスを作成すると、その列に同じ値を持つ複数の行がテーブルに含まれないことが保証されます。モデルでvalidates_uniqueness_of検証のみを使用するだけでは、同じデータを作成しようとする同時ユーザーが存在する可能性があるため、一意性を強制するのに十分ではありません。
2人のユーザーが、ユーザーモデルにvalidates_uniqueness_of:emailを追加した同じ電子メールでアカウントを登録しようとしていると想像してください。同時に[登録]ボタンを押すと、Railsはユーザーテーブルでそのメールを探し、すべてが正常であり、レコードをテーブルに保存しても問題がないことを返信します。 Railsは、2つのレコードを同じ電子メールでユーザーテーブルに保存します。これで、対処すべき非常に厄介な問題が発生します。
これを回避するには、データベースレベルでも一意の制約を作成する必要があります。
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email
...
end
add_index :users, :email, unique: true
end
end
したがって、index_users_on_email固有のインデックスを作成することにより、2つの非常に優れた利点が得られます。一意のインデックスは非常に高速になる傾向があるため、データの整合性と優れたパフォーマンス。
user_idの投稿テーブルにunique:trueを指定すると、同じuser_idで重複するレコードを入力できなくなります。