laravel-permission icon indicating copy to clipboard operation
laravel-permission copied to clipboard

Permissions are not updated once assigned a role

Open manstie opened this issue 1 year ago • 4 comments

Description

I was writing tests and came across this quirk.

Assuming you've given permission for a role to do a thing, this test still fails:

        $role = Role::find(1);
        $this->assertFalse($user->hasPermissionTo('do a thing'));
        $this->assertFalse($user->hasRole(1));
        $user->assignRole($role);
        $this->assertTrue($user->hasRole(1));

        $this->assertTrue($role->hasPermissionTo('do a thing'));
        $this->assertTrue($user->hasPermissionTo('do a thing')); // fails here, same thing with `->can('do a thing');`

But it works if you don't check permissions before assigning the role:

        $role = Role::find(1);
        // Works now that this is commented out
        // $this->assertFalse($user->hasPermissionTo('do a thing'));
        $this->assertFalse($user->hasRole(1));
        $user->assignRole($role);
        $this->assertTrue($user->hasRole(1));

        $this->assertTrue($role->hasPermissionTo('do a thing'));
        $this->assertTrue($user->hasPermissionTo('do a thing')); // works fine

I assume this is some caching issue.

Steps To Reproduce

In the same function:

  1. Check a user for permissions
  2. Assign a role
  3. Check user has permission in that role
  4. Fail

Example Application

https://github.com/manstie/laravel-permissions-example

Version of spatie/laravel-permission package:

6.9

Version of laravel/framework package:

11.9

PHP version:

8.2

Database engine and version:

No response

OS: Windows/Mac/Linux version:

No response

manstie avatar Sep 26 '24 01:09 manstie

I would expect that calling ->assignRole() would clear any associated cached relations (It does when I use Tinker).

Checking for a permission will load the permissions relation on the model, but then we destroy and reload that when roles/permissions are changed for that model. That said, Laravel lets you force a refresh: After you assign the role, call $user = $user->fresh();

Quick test in Tinker using some data similar to what's in the docs:

$user = User::first();
$role = Role::find(1); // 'Writer', with one permission: 'edit articles'
$before = $user->hasPermissionTo('edit articles');
$user->assignRole($role);
$afterRole =$user->hasRole(1);
$after = $user->hasPermissionTo('edit articles');

dd(compact('before', 'after'));
array:2 [
  "before" => false
  "after" => true
]

drbyte avatar Sep 26 '24 02:09 drbyte

It may be worth adding that I am using the "teams" feature, and I get the same results in tinker, even with $user = $user->fresh(): image

manstie avatar Sep 26 '24 03:09 manstie

This is isolated to your tests? If so, can you update the Issue Title to include that factor.

This package's test suite does extensive testing of adding and checking roles and permissions to ensure there are no caching issues, etc.

If you can create a simple fresh app (the Docs have a section on creating a new app and pushing it to a public github repo) that recreates this specific problem, we can determine whether this is a package bug or a bug in your application, and figure out the fix.

drbyte avatar Sep 26 '24 17:09 drbyte

I have created an app replicating my environment and settings here: https://github.com/manstie/laravel-permissions-example

~~Something to note: I seed the users with roles, but when you query them via the user model they are not found, despite existing in the database. I suppose that's my issue or it's related.~~ I wasn't setting the team id in my tinker session

manstie avatar Oct 01 '24 10:10 manstie

Dear contributor,

because this issue seems to be inactive for quite some time now, I've automatically closed it. If you feel this issue deserves some attention from my human colleagues feel free to reopen it.

spatie-bot avatar Feb 11 '25 11:02 spatie-bot

boo

manstie avatar Feb 24 '25 06:02 manstie