Railsのエラー『ActiveRecord::RecordNotUnique: Duplicate entry』の解決方法

Railsのエラー『ActiveRecord::RecordNotUnique: Duplicate entry』の解決方法

このエラーは、データベースの一意制約(UNIQUE制約)に違反するデータを挿入または更新しようとした場合に発生する。主に、モデルのバリデーション不足や、トランザクションの競合が原因であることが多い。この記事では、エラーの原因と解決方法について詳しく説明する。

エラーメッセージの例

ActiveRecord::RecordNotUnique: Duplicate entry 'example@example.com' for key 'users.email'

エラーの発生条件

  • 一意制約を持つカラムに重複した値を挿入しようとした
  • データベースのユニークインデックスに違反するデータを保存しようとした
  • 並列処理による競合が発生した
  • バリデーションの不足により、同じ値が登録されてしまった

データベースレベルでの一意制約の確認

データベースに設定されている一意制約を確認するには、以下のSQLを実行する。

SHOW CREATE TABLE users;

ActiveRecordのバリデーションを確認

モデルでvalidates :email, uniqueness: trueのようなバリデーションが設定されているかを確認する。

class User < ApplicationRecord
  validates :email, uniqueness: true
end

バリデーションの追加

バリデーションが不足している場合は、uniqueness: trueを追加する。

class User < ApplicationRecord
  validates :email, uniqueness: { case_sensitive: false }
end

データベースのユニークインデックスを確認

一意制約が適用されていない場合は、マイグレーションを作成する。

class AddUniqueIndexToUsers < ActiveRecord::Migration[6.0]
  def change
    add_index :users, :email, unique: true
  end
end

トランザクションによる競合の対策

並列処理による競合が発生する場合、rescueを使用してエラーを回避できる。

begin
  user = User.create!(email: "example@example.com")
rescue ActiveRecord::RecordNotUnique
  puts "Duplicate entry detected. Skipping creation."
end

アップサート(upsert)の活用

データを挿入する際に、重複がある場合は更新する方法。

User.upsert({ email: "example@example.com" }, unique_by: :email)

エラーが発生したデータの調査

データベース内で重複しているデータを確認する。

User.upsert({ email: "example@example.com" }, unique_by: :email)

まとめ

  • ActiveRecordのvalidates :uniquenessを確認
  • データベースの一意制約を確認
  • ユニークインデックスを適切に設定
  • トランザクションの競合を防ぐ
  • アップサートを活用する