こんにちは、かつコーチです。
前回は、セッションとフラッシュメッセージの使い方を解説しました。
ここまでで、フォームを受け取り、バリデーションし、結果をフラッシュメッセージとして保存する、という一連の流れが揃いました。
最後に必要になるのが、「処理が終わったあと、どの画面に移動させるか」を制御するリダイレクトです。
同じ「ページを移動させる」という処理でも、Laravelにはいくつかの書き方があります。
今回は、それぞれのパターンと使いどころを整理していきます。
リダイレクトとは?
ブラウザに別のURLへの移動を指示する仕組み
リダイレクトとは、サーバーがブラウザに対して「別のURLに移動してください」と指示するレスポンスのことです。
たとえばフォーム送信後にそのまま同じ画面を表示し直すと、ユーザーがブラウザの再読み込みをしたときに「フォームの再送信」を促す警告が出てしまうことがあります。
これを防ぐために、処理が完了したら一度別のURL(一覧画面や完了画面)にリダイレクトし、そのURLに対して改めて画面を表示する、という流れが定番になっています。
これは「Post/Redirect/Get(PRG)パターン」と呼ばれる、Web開発でよく使われる設計です。
基本の書き方
もっともシンプルなのが redirect() ヘルパー関数です。
<?php
return redirect('/contact');
指定したパスへ、302(一時的な移動)のステータスコードでリダイレクトします。
前回解説したフラッシュメッセージと組み合わせるのが、実務でもっとも頻繁に登場するパターンです。
<?php
return redirect('/contact')->with('message', '送信が完了しました。');
よく使うリダイレクトのパターン
パターン1:固定のURLを指定する
もっとも単純なのが、文字列でURLを直接指定する方法です。
<?php
return redirect('/contact/complete');
移動先のパスが変わることがほとんどないような、単純な画面遷移で使われます。
ただし、後述する理由から、実務ではこの書き方は徐々に別の方法に置き換えられていくことが多いです。
パターン2:直前のページに戻る(back)
バリデーションエラーのときによく使われるのが、back() ヘルパーです。
<?php
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|max:50',
'email' => 'required|email',
]);
// ...保存処理...
return redirect('/contact/complete');
}
実は、validate() メソッドがバリデーションに失敗した場合、内部的に自動で back() と同じ動きをしてくれています。
そのため、エラー時のリダイレクトを自分で書く必要はありません。
自分で明示的に back() を使うのは、独自のエラーチェックで「入力し直してほしい」という場面です。
<?php
public function confirm(Request $request)
{
if ($request->input('agree') !== 'yes') {
return back()->with('error', '利用規約への同意が必要です。');
}
return redirect('/register/complete');
}
パターン3:コントローラのアクションを指定する
コントローラのメソッド名を直接指定してリダイレクトする方法もあります。
<?php
use App\Http\Controllers\ContactController;
return redirect()->action([ContactController::class, 'index']);
URLを直接書く方法との違いは、コントローラ側でルーティングが変わった場合でも、コードを書き換えずに追従できる点です。
ただし、この方法もあまり主流ではありません。
パターン4:Named Routeを使う(実務での主流)
実務でもっともよく使われるのが、ルートに名前をつけておき、その名前でリダイレクトする方法です。
<?php
return redirect()->route('contact.complete');
ルート定義側で、あらかじめ名前をつけておきます。
<?php
// routes/web.php
use App\Http\Controllers\ContactController;
Route::get('/contact/complete', [ContactController::class, 'complete'])->name('contact.complete');
この書き方の最大のメリットは、URLの文字列を直接コードに書かなくて済むことです。
「もし将来 /contact/complete というURLを /inquiry/thanks に変更したくなったら?」と考えてみましょう。
URLを直接書く方法だと、コード中の該当箇所をすべて検索して書き換える必要があります。
Named Routeを使っていれば、ルート定義ファイルの1箇所を直すだけで、リダイレクト元の記述はそのままで済みます。
Named Routeの詳しい仕組みについては、次回の記事で改めて詳しく解説します。
つまずきやすいポイント:URLを直接書いてリンク切れを量産した話
一括置換で見落としが発生した
私が実務でリダイレクトを書き始めた頃、すべて文字列のURLを直接指定するスタイルで書いていました。
<?php
return redirect('/mypage/orders');
ある日、URL設計の見直しで /mypage/orders を /account/orders に変更することになりました。
❌ Before:URLを直接書いていたため、変更漏れが多発した
<?php
// コントローラA
return redirect('/mypage/orders');
// コントローラB
return redirect('/mypage/orders')->with('message', '注文を確定しました。');
// コントローラC(正規表現検索で見落としていた1箇所)
return redirect('/mypage/orders/'); // 末尾にスラッシュがついていて検索に引っかからなかった
エディタの一括置換で /mypage/orders を検索したのですが、末尾にスラッシュがついた書き方や、他の変数と文字列結合されていた箇所を見落としてしまい、一部の画面だけ古いURL(存在しないページ)にリダイレクトされる不具合を出してしまいました。
✅ After:Named Routeにしておき、URL変更に強くする
<?php
// ルート定義(routes/web.php)を1箇所直すだけでよい
Route::get('/account/orders', [OrderController::class, 'index'])->name('orders.index');
<?php
// コントローラA・B・C すべて共通
return redirect()->route('orders.index');
Named Routeにしておけば、URLそのものを直接書いている箇所はルート定義の1行だけになります。
この一件以来、「リダイレクト先が3箇所以上のコントローラから参照される可能性があるなら、最初からNamed Routeにしておく」というのを自分の中のルールにしています。
応用・一歩先の使い方
intended()でログイン前のページに戻す
会員限定ページに未ログインの状態でアクセスすると、ログイン画面に転送され、ログイン後は元のページに戻ってほしい、という要件はよくあります。
Laravelにはこれを実現する intended() というメソッドが用意されています。
<?php
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (auth()->attempt($credentials)) {
return redirect()->intended('/dashboard');
}
return back()->with('error', 'メールアドレスまたはパスワードが違います。');
}
intended() は、ログイン前にアクセスしようとしていたURLが記録されていればそのURLへ、記録がなければ引数で指定したURL(この例では /dashboard)へリダイレクトしてくれます。
自前で「元のURLをセッションに保存して、ログイン後に取り出す」処理を書く必要がないので、認証まわりの実装では覚えておくと便利です。
パラメータ付きでリダイレクトする
Named Routeで、URLの中に動的なID(例:/orders/{id})が含まれる場合は、第2引数にパラメータを渡します。
<?php
// routes/web.php
Route::get('/orders/{order}', [OrderController::class, 'show'])->name('orders.show');
<?php
// コントローラ
return redirect()->route('orders.show', ['order' => $order->id]);
// モデルを直接渡すこともできる(idが自動で使われる)
return redirect()->route('orders.show', $order);
モデルのインスタンスをそのまま渡せる書き方は、コードが簡潔になるのでよく使われます。
まとめ
この記事のポイント
- リダイレクトは、フォーム送信後などにブラウザへ別URLへの移動を指示する仕組み(PRGパターン)
- 直前のページに戻したいときは
back()、バリデーションエラー時は自動で同様の動きになる - URLを直接書く方法は変更に弱く、実務ではNamed Route(
redirect()->route())が主流 - ログイン前のURLへ戻したいときは
intended()が便利 - URLパラメータが必要な場合は、
route()の第2引数にモデルや配列を渡せる
次に読むべき記事
リダイレクトの書き方が整理できたら、次はここで何度も登場したNamed Routeの仕組みを、ルーティング設計の視点から詳しく見ていきましょう。
→ 次の記事:Named Routeでルートに名前をつけるメリット