dsmI's avatar
Level 3

Multiple parameters to crud

Hi, I'm having, probably a basic issue for some, problems with my edit crud.

I have this two routes in my web.php.

// Categories
Route::resource('docs', 'CategoryController');

// Articles
Route::resource('docs/{category}/', 'ArticleController');

The categories rout generates the url docs/category_name, by having it I can create categories in separate table.

The second route is for creating articles. I'd like to display it like docs/category_name/article_name.

But then I get the error "Missing required parameters for [Route: store] [URI: docs/{category}]"

This is my edit crud:


public function create($category)
{
    return view('articles.create')
    ->with('category', $category);
}

Still does it not work.

In my articles.edit file I have the following:

{!! Form::open(['route' => 'store']) !!}

I can't find where I'm wrong. Please provide me with some valuable information. Thank you!

0 likes
26 replies
arthurvillar's avatar

Probably you just need to specify the model like this

public function create(Category $category)
{
    return view('articles.create')
    ->with('category', $category);
}
dsmI's avatar
Level 3

I did specify the Model, but then "Sorry, the page you are looking for could not be found.". And I am still stuck.

arukomp's avatar

the first parameter of Route::resource is the name of the resource, not the url. Try this:

Route::resource('categories', 'CategoriesController');
Route::resource('articles', 'ArticlesController');

then you'll be able to access the routes using the names:

route('articles.show', $article);
...
route('categories.create');
dsmI's avatar
Level 3

Yes, but to get the url like I listed above, do I need to use a separate Route:get?

arthurvillar's avatar

The answer @arukomp gave you is perfect, I didn't pick up on that error. I have a feeling you should not be using resource at all, at least until you get used to how they work. You will have more control if you just write one get() method for each route you want.

Snapey's avatar

You cannot have the two routes as you have shown

// Categories
Route::resource('docs', 'CategoryController');

// Articles
Route::resource('docs/{category}/', 'ArticleController');

because the router cannot differentiate between docs/23 and docs/puppies

All your requests will go to the Category controller and not the to Article.

If you want to use Route::resource then you have to recognise that Article and Category are different resources and should have their own URLs

dsmI's avatar
Level 3

Okay, I understand. So in short, Route::resource gives the curds it's own URLs. So If I want it to be like a did it above I'll be needing to use Route::get except for put and delete?

Drfraker's avatar

@dsml you can type

php artisan route:list 

in the console and see all of the routes in your app. This might help you understand what the resource routes are creating for you.

Snapey's avatar

You would see the problem more clearly if you listed the routes out, but you would possibly still need to change the url schema

  • docs/23 to show document 23
  • docs/puppies to show category 'puppies'

cannot co-exist

  • docs/category/puppies
  • docs/23

can co-exist if they are in that order since category is matched before trying the variable route with the document ID

1 like
dsmI's avatar
Level 3

Yes, I see. So how can I sort my articles by category and link them like docs/main/some_article_name?

I already applied some hasToMany and BelongsTo in both Models.

Snapey's avatar

What data you return has little to do with the URL

You can pretend to use the category

Route::get('/docs/{category/{slug}','ArticleController@show');

and then in the controller

public function show($category, $slug)
{

    $article = Article::where('slug',$slug)->first();

and then never use the category if you have unique slugs for the articles.

dsmI's avatar
Level 3

So this two can't co-exist. That's now pretty clear. But if I create a PagesController and make a page called docs, can I then somehow get the collection of all categories and articles there or do I need I helper function for that? Thank you!

Snapey's avatar
  1. Your route calls a controller method.

  2. The method gets the data it needs and passes it to the view

  3. You return the view.

Your controller can get data from any of your models and pass as many variables to the view as required.

dsmI's avatar
Level 3

I did everything you suggested. I have now to separate controllers for the articles and categories. I'll make them only accessible for admin. Then I have the PageController for the other stuff, but because I use slug for both of the categories and the articles if I want to say docs/{slug}/{slug} I then get the error "Route pattern "/docs/{slug}/{slug}" cannot reference variable name "slug" more than once." Is there a way around? I'm using laravel-sluggable by spatie. Thank you!

dsmI's avatar
Level 3

I used this Route::get('/docs/{cat}/{slug}', 'PageController@article')->name('article');, where I only get the collection of the categories/the articles by category, but not the article itself. I'm getting "Sorry, the page you are looking for could not be found."

Snapey's avatar

What URL did you use to get page not found?

You are only giving half of the information all the time.

dsmI's avatar
Level 3

I'm using docs/ for the collection of the categories, then docs/category_name/ for the collection of the articles per category and last docs/category_name/article_name for the article itself.

Routes I'm using:

Route::get('/docs', 'PageController@categories')->name('categories');
Route::get('/docs/{cat}', 'PageController@category')->name('category');
Route::get('/docs/{cat}/{slug}', 'PageController@article')->name('article');

PageController:

/**
 * @return \Illuminate\Http\Response
 */
public function categories()
{
    $categories = Category::query()->get();
    return view('pages.categories.categories')
        ->with('categories', $categories);
}

/**
 * @return \Illuminate\Http\Response
 */
public function category($slug)
{
    $category = Category::whereSlug($slug)
        ->firstOrFail();
    return view('pages.categories.category')
        ->with('category', $category);
}

/**
 * @return \Illuminate\Http\Response
 */
public function article($slug)
{
    $article = Article::whereSlug($slug)
        ->firstOrFail();
    return view('pages.articles.article')
        ->with('article', $article);
}
Snapey's avatar

What URL did you use to get page not found?

Snapey's avatar
/**
 * @return \Illuminate\Http\Response
 */
public function category($slug)
{
    $category = Category::whereSlug($slug)
        ->firstOrFail();
    return view('pages.categories.category')
        ->with('category', $category);
}

This should be accepting $cat not $slug

dsmI's avatar
Level 3

What do you mean "What URL did you use to get page not found?". I already gave u the url. It was docs/category/name. The docs and category are working fine, when I come to name it shows me that the page was not found. For linking to the page I have this: {{ route('article', [$category->slug, $article->slug]) }}.

Snapey's avatar

You have not mentioned the URL - only the route

So, when you get page not found, the address bar says http://yourhost.dev/docs/category/name and you have an article in the database with a slug of name ?

->firstOrFail(); will return 404 if you have no article matching name

dsmI's avatar
Level 3

Yes I skipped the HTTP part. I know what ->firstOrFail(); does and there is a slug with the article name I try to access. I think the problem lies here: Route::get('/docs/{cat}/{slug}', 'PageController@article')->name('article');.

If I revers the link like {{ route('article', [$article->slug, $category->slug]) }}, article first and then the category, I can access both the category and the article. Only then I get http://yourhost.dev/docs/name/category.

Snapey's avatar

Well I can't really help I'm afraid because you seem incapable of comparing what is in the address bar with the name of the article.

If you don't want to share then fine.

Here's a tip for free

{{ route('article', ['slug'=>$article->slug, 'cat'=>$category->slug]) }}
dsmI's avatar
Level 3

What do I have to share? I showed you my code.

P.S. I solve my problem. I didn't have to provide the slug param on the article method, as I was just showing a particular article. Everything works fine now. Although I may switch to ASP.NET Core 2 just because my limited knowledge of Laravel.

verdothy's avatar

I ran into the same problem and what I had to do is put the Route::get before the Route::resource like this...

Route::get('/home', 'HomeController@index')->name('home');
Route::get('customers/archived', 'CustomerController@archived')->middleware('auth');
Route::get('customers/undelete/{id}', 'CustomerController@undelete')->middleware('auth');
Route::resource('customers', 'CustomerController')->middleware('auth');

Please or to participate in this conversation.