Rolify remove_role deletes from role table?
rolify, ruby-on-rails-3.2
Solution
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.
Problem
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 ```