こんにちは、かつコーチです。
前回は、リダイレクト処理のパターンについて解説しました。
その中で redirect('/mypage') のようにURLを直接書くコードが何度か出てきましたが、実は現場のLaravelコードではあまり見かけません。
代わりに使われるのが、今回紹介するNamed Route(名前付きルート)です。
「ルートに名前をつけるだけで、何がそんなに便利なの?」と思うかもしれませんが、実際に使ってみると手放せなくなる機能です。
Named Routeとは?
ルートに名前というラベルをつける仕組み
Named Routeとは、ルート定義に一意の名前をつけて、その名前でルートを呼び出せるようにする仕組みです。
通常のルート定義は、URLとコントローラの処理を結びつけるだけです。
Route::get('/user/profile', [ProfileController::class, 'show']);
このルートに name() メソッドで名前をつけると、Named Routeになります。
Route::get('/user/profile', [ProfileController::class, 'show'])->name('profile.show');
こうしておくと、Bladeテンプレートやコントローラの中で、URLを直接書く代わりに route('profile.show') という書き方でこのルートを参照できます。
なぜURL直書きではなくNamed Routeを使うのか
私が最初にLaravelを触ったとき、正直「別にURLを直接書けばいいのでは」と思っていました。
<a href="/user/profile"> と書くのも、route('profile.show') と書くのも、画面の見た目は同じだからです。
ですが、実際に小規模な管理画面を作ったときに、この考えの甘さを痛感しました。
途中で「/user/profile を /mypage/profile に変更したい」という要望が入り、リンクをgrepで探して1つずつ書き換える羽目になったのです。
Bladeファイル、コントローラのリダイレクト処理、メール送信テンプレート……URLを直書きしていた箇所が10箇所以上あり、1つ直し忘れて本番でリンク切れを起こしてしまいました。
Named Routeを使っていれば、Route::get() の1行を書き換えるだけで、参照している全箇所のリンクが自動的に更新されていたはずです。
この経験から、私はURLを2箇所以上で使い回す可能性があるルートには、必ずNamed Routeをつけるようにしています。
Named Routeの基本的な使い方
ルートに名前をつける
まずは基本の書き方をおさらいします。
// routes/web.php
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\PostController;
Route::get('/user/profile', [ProfileController::class, 'show'])->name('profile.show');
Route::get('/posts/{id}', [PostController::class, 'show'])->name('posts.show');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
名前は自由に決められますが、Laravelの慣習として「リソース名.アクション名」の形式(posts.show や posts.store など)で命名するのが一般的です。
Bladeテンプレートで使う
Bladeの中でリンクを生成するときは、route() ヘルパー関数を使います。
{{-- ❌ Before:URLを直接書く --}}
<a href="/user/profile">プロフィール</a>
<a href="/posts/{{ $post->id }}">{{ $post->title }}</a>
{{-- ✅ After:Named Routeを使う --}}
<a href="{{ route('profile.show') }}">プロフィール</a>
<a href="{{ route('posts.show', $post->id) }}">{{ $post->title }}</a>
{id} のようなパラメータが必要なルートは、route() の第2引数に値を渡せば自動的にURLへ組み込まれます。
コントローラのリダイレクトで使う
リダイレクト処理でも同じように使えます。
// ❌ Before:URLを直接書く
return redirect('/posts/' . $post->id);
// ✅ After:Named Routeを使う
return redirect()->route('posts.show', $post->id);
パラメータを複数渡したい場合は、配列で渡します。
Route::get('/posts/{id}/comments/{commentId}', [PostController::class, 'showComment'])
->name('posts.comments.show');
return redirect()->route('posts.comments.show', ['id' => $post->id, 'commentId' => $comment->id]);
Named Routeを使う3つのメリット
メリット1:URL変更に強くなる
一番のメリットは、先ほどの体験談でも触れた「URL変更に強い」という点です。
URLの構造を変えたくなったとき、Route::get() の第1引数だけを書き換えれば、route() を使っている箇所は自動的に新しいURLを返すようになります。
メリット2:タイプミスがエラーとして検出できる
URLを直接書いていると、/user/profile を /user/proflie のようにタイプミスしても、Laravelはそれをただの404として処理するだけです。
一方、存在しないルート名を route() に渡すと、RouteNotFoundException という例外が発生します。
// 存在しないルート名を指定すると、実行時に例外が発生する
route('profile.shwo'); // Route [profile.shwo] not defined.
画面が真っ白になるより、こうして早い段階でエラーとして気づける方が、修正のコストは圧倒的に低く済みます。
メリット3:現在のルートを判定しやすくなる
ナビゲーションメニューで「今どのページを開いているか」に応じてCSSクラスを切り替えたい、という場面はよくあります。
そんなときは request()->routeIs() を使うと、Named Routeの名前だけで判定できます。
<nav>
<a href="{{ route('posts.index') }}"
class="{{ request()->routeIs('posts.*') ? 'active' : '' }}">
投稿一覧
</a>
</nav>
posts.* のようにワイルドカードを使えば、posts.index や posts.show など、posts. から始まる全てのルートにマッチさせることもできます。
名前の付け方で気をつけたいこと
名前は重複させない
Named Routeの名前は、アプリケーション全体で一意である必要があります。
同じ名前を2つのルートにつけてしまうと、後から定義したルートの名前で上書きされてしまい、意図しないルートに飛んでしまうことがあります。
// ❌ Before:同じ名前を使い回してしまう
Route::get('/admin/posts', [Admin\PostController::class, 'index'])->name('posts.index');
Route::get('/posts', [PostController::class, 'index'])->name('posts.index'); // 上書きされる
// ✅ After:機能ごとにプレフィックスをつけて区別する
Route::get('/admin/posts', [Admin\PostController::class, 'index'])->name('admin.posts.index');
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
管理画面など、機能のまとまりが増えてきたら admin. のようなプレフィックスをつけて名前空間を分けておくと、後から見返しても迷いません。
グループでプレフィックスをまとめる
同じ接頭辞の名前を何度も書くのが面倒なときは、Route::name() をグループに適用すると、まとめて指定できます。
Route::prefix('admin')->name('admin.')->group(function () {
Route::get('/posts', [Admin\PostController::class, 'index'])->name('posts.index');
Route::get('/users', [Admin\UserController::class, 'index'])->name('users.index');
});
// 実際の名前は admin.posts.index、admin.users.index になる
name('admin.') のように末尾にドットをつけておくと、グループ内の各ルートで指定した名前の前に自動的に連結されます。
まとめ
この記事のポイント
- Named Routeは、ルートに名前をつけて
route()ヘルパーで参照できるようにする仕組み - URLを直接書くと変更時の修正漏れが起きやすいが、Named Routeなら定義を1箇所直すだけで済む
- 存在しないルート名を指定すると例外が発生するため、タイプミスに早く気づける
request()->routeIs()で現在のルートを判定し、ナビゲーションのアクティブ表示にも活用できる- ルート名は重複を避け、機能ごとにプレフィックスで整理するのがおすすめ
次に読むべき記事
次回は、URLのパラメータからモデルを自動的に取得してくれる「Route Model Binding」を解説します。
→ 次の記事:Route Model Bindingで自動的にモデルを取得する