読者です 読者をやめる 読者になる 読者になる

一意性制約はDB側で実現しなきゃ駄目

一意性制約をDB側で実現すべき理由

Railsチュートリアルに、 一意性制約はコード(Active Record)側ではなくてDB側で実装すべきという注意があったのでメモ。

理由は、以下のようなことが起こり得るから。

  1. 登録ボタンが素早く2回クリックされた場合にリクエストが2つ連続で送信される。
  2. リクエスト1は検証にパスするユーザーをメモリ上に作成する。
    リクエスト2も同様にメモリ上に作成する。
    (ここで valid? メソッドにより一意性の検証が行われるが、この時点ではどちらのデータもDBに登録されていないので通過してしまう)
  3. 結果、一意性の検証が行われているにも関わらず、同じメールアドレスを持つ2つのユーザーレコードが作成されてしまう。

対策

DB側で一意性制約を設定する。

class AddIndexToUsersEmail < ActiveRecord::Migration
  def change
    add_index :users, :email, unique: true
  end
end