Route Model Binding
Look at almost any show, edit or update method and its first line is the same: take the id, look up the record, 404 if it is missing. Lendly would repeat Book::findOrFail($id) in dozens of places. Route model binding makes Laravel do that line for you.
The rule
Same name, model type: Laravel fetches it or sends 404.
Before:
Route::get('/books/{id}', [BookController::class, 'show']);
public function show(string $id)
{
$book = Book::findOrFail($id);
return view('books.show', ['book' => $book]);
}After:
Route::get('/books/{book}', [BookController::class, 'show']);
public function show(Book $book)
{
return view('books.show', ['book' => $book]);
}Two things must line up:
- The URI segment is
{book}, and the argument is$book. The names match. - The argument is type-hinted with the model,
Book.
Then, for /books/12, Laravel runs the lookup by primary key and passes in the finished Book. For /books/9999 with no such row, it sends a 404 and your method never runs.
Looking up by another column. Put the column after a colon in the URI:
Route::get('/books/{book:slug}', [BookController::class, 'show']);Now /books/dune fetches the book whose slug is dune. To make a column the default for every route, override getRouteKeyName() on the model to return 'slug'.
It works in closures too: Route::get('/books/{book}', fn (Book $book) => $book->title);.
The shortcut
Scan the route and the signature side by side and ask "does the brace name match a type-hinted model variable?" If yes, the lookup and the 404 are handled. If the names differ, you get no binding.
The route
Route::get('/books/{id}', [BookController::class, 'show']).
That empty-model result is the trap. There is no error, just a blank page with no title, so compare names first.
Drills
Answer fast — trust the rule.
Which pairing binds a Member model automatically?
With binding in place, what does /books/9999 return when no such book exists?
Which route fetches a book by its isbn column?
How do you make every Book route look up by slug by default?
Remember
- Same name, model type: Laravel fetches it or sends 404.
- Compare brace name and variable name first.
- Trap: mismatched names give an empty model, not an error.
