ルートパラメータを定義するときに注意すること
この記事で出てくるルーティングとは何かについて知りたい方は以下よりどうぞ
Laravelのバージョン
$ php artisan -V
Laravel Framework 9.26.1
エラー
前提条件
- 簡単なブログアプリを作っている
- ブログアプリには投稿一覧ページ(
index
),投稿詳細ページ(show
),投稿作成ページ(create
)の3種類のページがある. - それぞれのページは
PostController
のindex
メソッド,show
メソッド,create
メソッドによって表示出来るように実装した(詳細は省略).
ブログアプリ
ルーティングは以下のようになっています.
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
Route::get('/', [PostController::class, 'index']);
Route::get('/posts/{post}', [PostController::class, 'show']);
Route::get('/posts/create', [PostController::class, 'create']);
...(以下省略)...
ルートパラメータについて
ルートパラメータとは,上のweb.php
内の{post}
となっている部分のことを指します.
ブログアプリの構造からわかるように,投稿が複数あり,それぞれにidがついています(図ではid=3
のshowページ(/posts/3
)を表示しています).
このとき,以下のようにidごとにルーティングを用意するのはナンセンスですよね.
- Route::get('/posts/{post}', [PostController::class, 'show']);
+ Route::get('/posts/1', [PostController::class, 'show1']);
+ Route::get('/posts/2', [PostController::class, 'show2']);
+ Route::get('/posts/3', [PostController::class, 'show3']);
そこで,{post}
の部分に任意のパラメータを受け取り,それをpost
というキーでコントローラに渡すようにすると,投稿の数がいくら増えても,show
メソッドは一つで済みます.
発生したエラー
ということで,さっそくブログアプリを使ってみたいと思います.
・・・
あれ?
エラー
show
ページは表示されるのに,create
ページはNot found
のエラーが出てしまいました.
なぜでしょう?
・・・
原因
なぜこのようなエラーが出てしまったのでしょう.
index
ページでcreate
ボタンが押されたところから処理の流れを辿っていきましょう.
-
create
ボタンが押される -
web.php
が/posts/create
というURLをGETメソッドで受け取る -
web.php
が上記のリクエストに合致するルーティングをファイルの上の行から順に探す -
show
メソッドの行のルーティングと合致する
・・・
ん?なんで?と思いますよね.
しかし,この場合/posts/create
はcreate
メソッドより先にshow
メソッドと合致してしまいます.
これは,
です.
つまり,{post}
の部分にcreate
が入ってしまったということです.落とし穴みたいですね.
ルートパラメータの落とし穴
これにより,show
メソッドが実行され,その時にpost
というキーでcreate
という文字列がコントローラに渡されてしまうため,「リソース(ページ)が見つかりません」という意味のNot found
エラーが出てしまうのですね.
対処
どうすればこのエラーを回避しつつ,ルートパラメータを利用することが出来るでしょう?
・・・
私は主に2つの対処法があると思います(他にもあるかもしれないので自身でもぜひ考えてみてください).
-
show
メソッドとcreate
メソッドのweb.php
内での記述順を入れ替える -
show
メソッドのURLを変更する
それぞれ説明していきます.
show
メソッドとcreate
メソッドのweb.php
内での記述順を入れ替える
1. web.php
を以下のように修正します.
- Route::get('/posts/{post}', [PostController::class, 'show']);
Route::get('/posts/create', [PostController::class, 'create']);
+ Route::get('/posts/{post}', [PostController::class, 'show']);
こうすることで,落とし穴にはまる前に目的地にたどり着くことが出来ます.
対処法1
ただ,ルーティングの数が増えていくとどのように順序を変えればいいかが分かりづらくなっていくという懸念点があります.
show
メソッドのURLを変更する
2. web.php
を以下のように修正します.
- Route::get('/posts/{post}', [PostController::class, 'show']);
+ Route::get('/posts/{post}/show', [PostController::class, 'show']);
Route::get('/posts/create', [PostController::class, 'create']);
こうすることで,URLが別物になるので,落とし穴はなくなります.
対処法2
ただ,URLは「リソースを表す固有名詞」で構成されることが望ましい(RESTful)ので,あまりクールなURLとは言えないという懸念点があります.
まとめ
ルートパラメータの利用目的とその落とし穴について説明しました.
大切なのは
ということです.
また,対処法については,ともに懸念点が残るので,クールでスマートな対処法があれば教えてください.
では,
参考
Discussion
僕が思いついたアプローチとしては、記事内の方法に加えて
{post}
にwhere
メソッドやwhereNumber
メソッドを使って{post}
に入る値を制限するのもありかな、と思いました!🙆♂️Laravelは正規表現などでルートパラメータに制約をかけられるんですね。
コメントいただきありがとうございます!
その認識で合っています!🙆♂️
他のヘルパメソッドもありますので、調べられてみるといいかも知れません!👍