【Laravel】Named Routeでルートに名前をつけるメリット

laravelアイキャッチ Laravel

こんにちは、かつコーチです。

前回は、リダイレクト処理のパターンについて解説しました。

その中で 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.showposts.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.indexposts.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で自動的にモデルを取得する

タイトルとURLをコピーしました