This is strange. I'm using Rolify + CanCan + Devise in my rails 3.2 app. My use case is simple. I want a user to have only one role at a time, thus to change a role, I do something like this:
user.remove_role "admin"
user.add_role "associate"
The strange thing to me is that when I do this, the role "admin" gets deleted from the Roles table. Why would this be? I don't want to eliminate the role entirely, just a given role from the user. What am I doing wrong?
Here's the SQL. Notice the last delete from roles statement:
3] pry(main)> u.remove_role "sub_admin"
Role Load (0.1ms) SELECT "roles".* FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = 2 AND "roles"."name" = 'sub_admin'
(0.0ms) begin transaction
(0.3ms) DELETE FROM "users_roles" WHERE "users_roles"."user_id" = 2 AND "users_roles"."role_id" IN (2)
(1.9ms) commit transaction
User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "users_roles" ON "users"."id" = "users_roles"."user_id" WHERE "users_roles"."role_id" = 2
(0.0ms) begin transaction
SQL (2.1ms) DELETE FROM "roles" WHERE "roles"."id" = ? [["id", 2]]
(0.6ms) commit transaction
In the REST API, you remove a role assignment by using Role Assignments - Delete. Get the role assignment identifier (GUID). This identifier is returned when you first create the role assignment or you can get it by listing the role assignments.
To remove role assignments, you must have: Open Access control (IAM) at a scope, such as management group, subscription, resource group, or resource, where you want to remove access. Click the Role assignments tab to view all the role assignments at this scope.
Azure role-based access control (Azure RBAC) is the authorization system you use to manage access to Azure resources. To remove access from an Azure resource, you remove a role assignment. This article describes how to remove roles assignments using the Azure portal, Azure PowerShell, Azure CLI, and REST API.
Click the Role assignments tab to view all the role assignments at this scope. In the list of role assignments, add a checkmark next to the security principal with the role assignment you want to remove. Click Remove. In the remove role assignment message that appears, click Yes.
The basic problem is that each combination if role-name, resource_type, and resource_id is stored only once in the roles
table. If you delete this row, it is deleted for everyone.
The solution then is to delete only the rows from the join table
of rolify connecting the User
and the Role
models. For ease of access i will make the join table a model to use some rails magic to generate the SQL. Since this is really a kind of service object, i will make it a class singleton.
Here is my hack:
class UsersRoles < ActiveRecord::Base
def self.delete_role(subject,role_symbol, obj=nil)
res_name = obj.nil? ? nil : obj.class.name
res_id = obj.id rescue nil
role_row = subject.roles.where(name: role_symbol.to_s, resource_type: res_name , resource_id: res_id).first
if role_row.nil?
raise "cannot delete nonexisting role on subject"
end
role_id = role_row.id
self.delete_all(user_id: subject.id,role_id: role_id)
end
private_class_method :new
end
This code is not optimized, but should give you idea what to do: for example you can now add a convenience method to the User
model:
def delete_role(role_symbol,target=nil)
UsersRoles.delete_role self,role_symbol,target
end
then you can say:
user.delete_role :admin
and it will only remove what you want.
Note that this will not remove the table row with the role, which I would retain for future use.
I know this question is more than two years old, but I found better and more "rolify like" answer.
You can do it really easy in User model:
def remove_only_role_relation(role_name)
roles.delete(roles.where(:name => role_name))
end
and use it like:
@user = User.find_by_id(params[:id])
role_name = params[:role_name]
# or:
# role_name = Role.find_by_id(params[:role_id]).name rescue nil
if @user and role_name
@user.remove_only_role_relation(role_name)
end
I found similar code in their sources:
rolyfi: role.rb - here method remove_role cals method "remove" in adapter file: rolyfi: role_adapter.rb
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With