論理削除済み&自分自身を除外するuniqueバリデーション
..
メールアドレスがログインID代わりに使用される場合などは、users
内のemail
カラムにユニーク制約を付加する必要があります。
加えて登録・更新時のバリデーションにおいても重複する値を弾く必要があるわけですが、User
モデルが論理削除に設定されている場合は、論理削除されたレコードの値は除外するようにルール側で対応する必要があります。
論理削除済みのレコードを除外する
新規ユーザー登録のバリデーションはこう。
'email' => 'required|unique:users,email,,,deleted_at,NULL|max:255|email:rfc,dns',
論理削除に設定する場合は、基本的にdeleted_at
カラムがNULLであることや、exist
カラムに1が入っていることで存在していることを判断することになります。
create_users_table.php
・
・
$table->boolean('exist')->nullable()->storedAs('case when deleted_at is null then 1 else null end');
・
・
$table->unique(['email', 'exist']);
ルールにもその条件を書くことで、バリデーション時に「存在しているユーザーのカラム」だけをチェックするようになります。
unique
ルールのパラメータは以下のような構成となっています。
- テーブル名(必須)
- カラム名(必須)
- 除外する値
- 除外するカラム
- 追加でチェックするカラム(例では
deleted_at
カラム) - 値の条件(例では
NULL
)
新規登録時は3,4番目を空欄にし、追加条件の部分で「deleted_at
がNULL
であること」を指定しています。
同一ユーザーのレコードを除外する
ユーザー情報更新画面があったとして、email
以外の部分を更新しようとした場合。
そのままだと自分自身のemail
と重複していると見做され、バリデーションエラーとなって更新できません。
ログイン後にアクセスするそうした画面においては、Auth
ファサード等でユーザーIDを取得し、それを除外します。
UpdateRequest.php
use Illuminate\Support\Facades\Auth;
・
・
・
$id = Auth::id();
return [
'email' => 'required|unique:users,email,'. $id .',id,deleted_at,NULL|max:255|email',
user/3/edit
などのURLであれば、ルートでID部分を変数化し、Requestクラス内で受け取ることも可能です。
web.php
Route::post('/user/{id}/edit', [UserController::class, 'update']);
UpdateRequest.php
use Illuminate\Support\Facades\Auth;
・
・
・
return [
'email' => 'required|unique:users,email,'. $this->id .',id,deleted_at,NULL|max:255|email',
これによって、「更新対象ユーザーを除いたユーザー」かつ「有効なユーザー」のレコードとのみ比較するように設定できます。