Laravelのバリデーションで’unique’を利用しているシステムは多いと思います。これにより重複したデータを弾くバリデーションを組むことができます。
そして論理削除(ソフトデリート)について。これはデータの削除を行う際にレコードを消すのではなく、フラグ(deleted_atなど)を用意してアプリケーション上は消したよう振る舞うものです。
今回は、上記のuniqueバリデーションと論理削除で少しハマった話です。
例としてvideosテーブルには論理削除を採用しています。そしてvideos.titleカラムにはuniqueバリデーションルールを適用しています。
しかしこの状態では、「論理削除済みのvideosのtitle」すらも再度登録ができません。
ユーザーからしたら「登録していないのに『既にデータがあります』ってエラー出る、なんだこれ使えね」となります。これが今回の問題です。
長くなりましたが、以下の通りuniqueのバリデーションを修正して対応しました。クエリビルダを使ってuniqueの条件をカスタマイズすることが可能です。
'title' => [
'required',
'max:400',
$this->rule
->unique($this->video->getTable())
// ソフトデリートされていないレコードが対象
->where(fn (Builder $query) => $query->whereNull('deleted_at')),
],
コメントの通りwhere句を追加し、deleted_atがnull(未削除のデータ)をuniqueの対象としました。
ただし最後に、videos.titleにunique制約張っている場合はもちろんクエリ実行時にコケます。
なので論理削除を採用する場合は対策なしだとunique制約と競合するのでご注意を。
▼参考(‘追加のWHERE節を付け加える’より)
https://readouble.com/laravel/10.x/ja/validation.html#rule-unique