The resource route will define the following routes:
Method Path Action
GET /makes/{make}/models index
GET /makes/{make}/models/create create
POST /makes/{make}/models store
GET /makes/{make}/models/{id} show
GET /makes/{make}/models/{id}/edit edit
PUT /makes/{make}/models/{id} update
DELETE /makes/{make}/models/{id} destroy
Your request /makes/ferrari/models will not match any of those routes (as your show parameter only takes one parameter). You may request for /makes/models/1 to call show, but you are practically missing the route for this, as the nested route does not provide it.
If you say that you always get all items, you are very likely hitting the index action instead of show.
If you want to query your models with /makes/ferrari/models/f40, you would need a route like this:
Route::get('/makes/{make}/model/{model}', 'ModelsController@show');
Which is already part of the resource route created for you.
Now, in your show controller, use the make and model parameters to find the correct dataset:
public function show($make, $model)
{
$data = Model::with('makes')
->whereName($model)
->whereHas('makes', function ($query) use ($make) {
$query->where('name', '=', $make);
})->get();
return response()->json($data);
}
Laravel doesn't automatically do that for you.
Update: Route model binding
You might want to check out https://laravel.com/docs/5.3/routing#route-model-binding for a more sophisticated way of doing this. You can set your route key name in both of your models overwriting the getRouteKeyName() method and returning 'name' in this case, telling Laravel to use the name column instead of the id.
You can also bind parameters in your routes specifically to a custom resolution logic by doing something like
$router->bind('model', function ($value) {
return Model::where('name', $value)->first();
});
and then every time you use {model} in your routes, it will use the name instead of the id.
Use slugs
However, be advised that you have to make absolutely sure that the names stored in the database for model and make are sluggified so that they are suited for use in URLs. If necessary, you may possibly do that in your bind as shown above, returning
return str_slug(Model::where('name', $value)->first());
This is untested, however, so it might or might not work.
Hope that helps :-)