I use Devise for authentication, Rolify for role management and CanCan 2.0 for authorization.
I am trying to allow: admin roles to change user roles, but deny access to all other users.
Here is what I tried and it doesn't work:
#ability.rb class Ability include CanCan::Ability def initialize(user) if user.has_role? :admin can :access, :all elsif user.has_role? :moderator can [:index, :read, :update, :destroy], :users, :user_id => user.id cannot :access, :users, [:role_ids] end end
I intentionally left the association in my user form:
#_form.html.erb <%= simple_form_for @user do |f| %> <%= f.association :roles, as: :check_boxes %> <%#= f.association :roles, as: :check_boxes if can? :update, @user, :roles %> <%= f.button :submit %> <% end %>
controller
and model:
#user.rb class User < ActiveRecord::Base rolify attr_accessible :role_ids ...
Now, if the user with the role: moderator is trying to change the role of another user (or his own), this is what happens:
- CanCan called :: Unauthorized exception and user is redirected to root_url
- Roles changed for user
I am embarrassed. If an exception occurs, why are the changes still made? I'm probably doing something really bad :)
I tried to manipulate the request parameters depending on the user role in users_controller.rb. If I set the log statement immediately after def was updated, here is my conclusion:
2013-04-24 12:42:21 [4161] DEBUG (0.1ms) BEGIN 2013-04-24 12:42:21 [4161] DEBUG (0.3ms) INSERT INTO "users_roles" ("user_id", "role_id") VALUES (5, 1) 2013-04-24 12:42:21 [4161] DEBUG (0.4ms) COMMIT 2013-04-24 12:42:21 [4161] DEBUG User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", "5"]] 2013-04-24 12:42:21 [4161] DEBUG {"username"=>"Blabla", "email"=>" bla@bla.com ", "password"=>"", "password_confirmation"=>"", "approved"=>"1", "role_ids"=>["1", "2", ""]}
I have to ignore something ...