鶏口牛後な日々

心の赴くまま、やりたいことを仕事に。

Laravelのedit/updateフォームでvalidationから1レコードだけ除外する

ユーザー情報の登録について、アップデートしたい場合に、登録時に例えばメールアドレスにバリデーションで unique をつけていた時、アップデート時は、そのメールアドレスはすでにその人のレコードではあるので、ユニークバリデーションから除外したい時ってありますよね。

でも、他の人のメールアドレスとは被らないことをチェックしてほしい。

そういう時は、uniqueルールの引数で、ignore(無視)するレコードを指定することができます。

バリデーションのリクエストファイルの、rulesに以下のルールを追加します。

unique:table,column,except,idColumn

Validation - Laravel - The PHP Framework For Web Artisans

このexcept というところに、チェックから外したいレコードの id を入れると良いようです。

実際に、userテーブルのemailカラムを重複させたくない場合、rules メソッドの中身は、以下のようになります。

$user = $this->route('user');
return [
     'email' => 'unique:users,email,'.$user->id,
];

この時、 $this->route('user') というところでは何をしているかというと、このリクエストファイルに到達するときのルート(=updateメソッドを呼び出すルート)に含まれているルートパラメータの user というのを取得しています。 つまり、ルートファイルのなかで、

Route::get('/users/{user}', 'UsersController@show');

とか書いていますよね。 ここでいうところの、 {user} で指定している文字列のことですね。

Laravelでは、ルートパラメーターに、id を挿入すると、自動的に、その id をもつモデル(ここでは User )を返してくれるので、 $user には、今アップデートしようとしているユーザーモデルが入るというわけです。

ただ、ルートパラメータに id 以外の何かを入れている場合は、自動でユーザーモデルを取得してはくれないので、 自分で取得する必要があります。

$alias_ = $this->route('user_alias');
$user = User::where('alias', $alias)->firstOrFail();

これで、 $user には、ユーザーモデルが入ってくれます。

rules の中に書いている、 $user->id というのは、取得したユーザーモデルのidをさすので、このレコードは、バリデーションのuniqueルールをチェックする時に除外してくれる、という寸法です。

ちなみに、こちらはバージョン5.3あたりから、新しいカスタムバリデーション的なものを作成する方法に変わってしまったらしいのですが、(記事を読んだのみで、未確認) 以前の書き方の方がシンプルだし、少なくとも2018年7月現在もまだ上記のやり方が通用することを確認しています。

以上。

参考:5.2の公式ドキュメント