delete() not working on laravel 8 controller

My Laravel Project have a resource controller named Blogpost, where in destroy method, the $blogpost->delete() approach doesn’t work. But if I use DB Query, it works just fine. See code below.

This doesn’t work:

public function destroy(Blogpost $blogpost)
{
    $blogpost->delete();
    
    return redirect()->route('blog.index');
}

This works perfectly:

public function destroy($id)
{
    $post = Blogpost::find($id); 
    $post->delete();

    return redirect()->route('blog.index');
}

In routesweb.php, I’m using resource route for this controller.

Route::resource('blog', BlogpostController::class);

Note: The Blogpost model have a hasMany() relationship with postViews model.

public function postViews()
{
    return $this->hasMany(PostViews::class);
}

Note: post_views table have a foreign key associate with blogpost table. See migration below:

$table->foreign('blogpost_id')
              ->references('id')
              ->on('blogposts')
              ->onDelete('cascade');

If I use dd($blogpost); it returns the model.

code:

public function destroy(Blogpost $blogpost)
{
    dd($blogpost);
}

Output:

dd() inside destroy method

My question is, why $blogpost->delete(); approach is not working? is it because of the hasMany() relationship?

PS: I have another resource controller named Category, where the $category->delete() approach works perfectly.

Answer

TL;DR Change your destroy method to be:

public function destroy(Blogpost $blog)
{
    $blog->delete();
    
    return redirect()->route('blog.index');
}

I would imagine the reason this is happening is because your route parameter is blog but your controller parameter is $blogpost i.e. they don’t match.

If you type hint a controller method parameter, Laravel will try and resolve an instance of it out of the container. This is why you get an instance of Blogpost but not the loaded instance you want. Route model binding won’t work here because the names have to match.