3
votes

I have Article model and articles table in the database. Each article can be shown using Laravel's standard URI structure: www.example.com/articles/5 (where 5 is the article id). Each article has a slug field (slug column in the articles table), so with Route Model Binding I use slug instead of id:

RouteServiceProvider.php:

public function boot(Router $router)
{
    parent::boot($router);

    \Route::bind('articles', function($slug) {
        return \App\Article::where('slug', $slug)->firstOrFail();
    });
}

In routes.php I have:

Route::resource('articles', 'ArticleController');

and now articles can be accessed with URLs like: www.example.com/some_slug .

But now, when I want to edit some article, I get the following error:

No query results for model [App\Article].

For example, when I try to open the following: www.example.com/some_slug/edit - I get that error.

So, method ArticleController@show(Article $article) works fine, but ArticleController@edit(Article $article) doesn't work.

Here is my route list:

Rote List

and here are show and edit methods from ArticleController:

public function show(Article $article)  // THIS WORKS FINE
{
    $tags = $article->tags()->get();
    return view('articles.show', compact('article', 'tags'));
}

public function edit(Article $article) // DOESN'T WORK -> When I open article/slug/edit I get error: No query results for model [App\Article].
{
    $tags = Tag::lists('name', 'id');
    $categories = Category::orderBy('lft', 'asc')->get()->lists('padded_name', 'id');
    return view('articles.edit', compact('article', 'tags', 'categories'));
}
3
you're missing the s at the end of your edit parameter. Should be edit(Article $articles) not edit(Article $article) in order to match /articles/{articles}Jeff Puckett

3 Answers

11
votes

If anyone wants to do route model binding with both id and slug, explicitly binding like this works:

// App\Providers\RouteServiceProvider::boot

Route::bind('product', function($value) {
   return \App\Product::where('id', $value)->orWhere('slug', $value)->first();
});
10
votes

I believe in 5.2, you can customize the key name directly in the model using the getRouteKeyName method:

public function getRouteKeyName()
{
    return 'slug';
}

docs

-4
votes

I have another approach for you without touching RouteServiceProvider.php. I hope it helps.
You need use App\Article; and use App\Tag; in your ArticleController.
ArticleController

public function show($slug)
    {
        $article = Article::where('slug', $slug)->first();

        $tags = Tag::lists('name', 'id');

        return view('articles.edit', compact('article', 'tags'));
    }

public function edit($slug)
    { 
        $article = Article::where('slug', $slug)->first();

        $tags = Tag::lists('name', 'id');

        return view('articles.edit', compact('article', 'tags'));
    }