Syi's avatar
Level 6

Policy not being called from Request via Gate

I have a custom request for updating and creating a model which calls a Policy via a Gate to authorize the request as in the documentation. The update ability works fine (although I ran into this same issue originally and can't remember how I got it working) but the create one doesn't seem to ever reach the Policy.

TargetUserCreateRequest.php

public function authorize(): bool
    {
        $client = $this->route('client');
        $response = Gate::inspect('create', $client);

        if ($response->allowed()) {
            return true;
        }

        return false;
    }

TargetUserPolicy.php

public function before(User $currentUser)
    {
        if ($currentUser->hasRole('system_admin')){
            return Response::allow();
        }
    }

    public function update(User $currentUser, Client $client, TargetUser $targetUser)
    {
        return $currentUser->hasAnyRole(['client_admin', 'client_manager']) &&
        ($currentUser->client->id === $client->id) &&
        ($currentUser->client->id === $targetUser->client->id) ?
            Response::allow() :
            Response::deny();
    }

    public function create(User $currentUser, Client $client)
    {
        Log::debug('Doesnt get logged');
        return $currentUser->hasAnyRole(['client_admin', 'client_manager']) &&
        ($currentUser->client->id === $client->id) ?
            Response::allow() :
            Response::deny();
    }

TargetController.php

public function usersSave(TargetUserCreateRequest $request, Client $client)
    {
        return 'Goal';
		//Will save the user once it gets here
    }

    public function userEdit(Client $client, TargetUser $targetUser)
    {
        Gate::authorize('update', $client, $targetUser);
        return Inertia::render('Targets/Users/Edit', [
           'targetUser' => $targetUser,
        ]);
    }

    public function userUpdate(TargetUserUpdateRequest $request, Client $client, TargetUser $targetUser)
    {
        $targetUser->update([
            'fname' => $request->fname,
            'lname' => $request->lname,
            'email' => $request->email,
            'job_title' => $request->job_title,
        ]);
        return back(303);
    }

Routes

Route::get('/client/{client}/targets/users/create', [TargetController::class, 'usersCreate'])->name('targets.users.create');
        Route::post('/client/{client}/targets/users/create', [TargetController::class, 'usersSave'])->name('targets.users.store');

I have a TargetUserUpdateRequest.php which is almost identical to TargetUserCreateRequest.php and works fine but no log messages get saved for the create request because it seems it doesn't run any of the code in the create() method.

If anyone can spot what I'm doing wrong it would be greatly appreciated

0 likes
1 reply
LaryAI's avatar
Level 58

The issue you're experiencing seems to be related to how the Gate::inspect method is being called in your TargetUserCreateRequest.php. The Gate::inspect method expects the policy method to be called with the correct number of arguments. In your case, the create method in the TargetUserPolicy expects two arguments: a User and a Client. However, it seems like you might not be passing the User correctly.

Here's a step-by-step solution to ensure that the create method in your policy is called correctly:

  1. Ensure the User is Authenticated: Make sure that the user is authenticated when the request is being made. The Gate will automatically use the currently authenticated user.

  2. Pass the Correct Arguments: When calling Gate::inspect, ensure that you are passing the correct arguments. The create method in your policy expects a User and a Client. The User is automatically inferred from the authenticated user, but you need to ensure the Client is passed correctly.

  3. Check the Route Binding: Ensure that the client route parameter is correctly bound and available in your request.

Here's how you can adjust your TargetUserCreateRequest.php:

public function authorize(): bool
{
    $client = $this->route('client');

    // Ensure the client is not null
    if (!$client) {
        return false;
    }

    // Use Gate::allows for a simpler check
    return Gate::allows('create', $client);
}
  1. Logging for Debugging: Add logging in your create method to ensure it's being called:
public function create(User $currentUser, Client $client)
{
    Log::debug('Create method called in policy');

    return $currentUser->hasAnyRole(['client_admin', 'client_manager']) &&
           ($currentUser->client->id === $client->id) ?
           Response::allow() :
           Response::deny();
}
  1. Check the Policy Registration: Ensure that your policy is correctly registered in the AuthServiceProvider:
protected $policies = [
    TargetUser::class => TargetUserPolicy::class,
];
  1. Verify the Controller Method: Ensure that the usersSave method in your controller is correctly set up to use the TargetUserCreateRequest.

By following these steps, you should be able to ensure that the create method in your policy is being called correctly. If the issue persists, double-check the route bindings and ensure that the Client model is being correctly resolved in your request.

Please or to participate in this conversation.