CanCanCommunity / cancancan

The authorization Gem for Ruby on Rails.
MIT License
5.57k stars 638 forks source link

Allow a user to change itself but not its role #857

Open marino-mrc opened 2 months ago

marino-mrc commented 2 months ago

Hi, I have a User model with an integer field containing its role. A User can have a single role only. Roles definition here: enum role: { superadmin: 0, admin: 1, member: 2}

Now, I want to configure abilities in a way that a 'member' user can change only itself (the email and the password) but cannot change its role. I tried in many ways:

if user.has_role? :member
    can :read, User, id: user.id
    can :update, User, role: "member", id: user.id
    ...

Also, I tried with the following lines: can :update, User, role: 2, id: user.id

Or can :update, User, role: :member, id: user.id

But no way, the user is always able to change its role to "superadmin". I'm not sure this is a bug or if I'm doing it in the wrong manner.

Please, let me know if this can be fixed in some way.

Ruby version: ruby 3.1.0p0 (2021-12-25 revision fb4df44d16) [x86_64-linux] CanCan version: cancancan (3.6.1) Rails version: rails (7.1.3.4)

Thank you. Regards, Marco

adamkiczula commented 1 month ago

You probably want to use either strong_parameters or accessible attributes or some combination of both.

Assuming you have want to allow other roles to edit role, you can do something like this (untested):

# Ability
# don't allow members to update their role
if user.has_role? :member
    can :update, User, [:email, :password], id: user.id
end
# allow superadmins to update roles for users
if user.has_role? :superadmin
    can :update, User, [:email, :password, :role]
end

# UsersController
def update_user_params
  params.require(:user).permit(*current_ability.permitted_attributes(:update, @user))
end