Reputation: 9701
Here is what I want to do:
A User
assigned an admin
role cannot update the role of a User
with the god
role. So here's the code I came up with:
if user.has_role? 'admin'
can :manage, :all
cannot :update, User do |resource|
resource.has_role?('god')
end
end
However, resource
seems to always return nil
.
Any ideas?
Upvotes: 0
Views: 91
Reputation: 7937
In order to be able to use the block syntax for #can
and #cannot
, you have to first load the resource in your controller. As doc says :
The block is only evaluated when an actual instance object is present. It is not evaluated when checking permissions on the class (such as in the index action). This means any conditions which are not dependent on the object attributes should be moved outside of the block.
For this instance object to be present, you need to let cancan load it:
class UsersController < ApplicationController
load_and_authorize_resource
end
This will make @user
available both in your controller and in your block passed to #cannot
. Now there's a catch.
CanCan has a problem with rails-4 : it does not handle StrongParameters. This causes automatic resource loading to crash on #create
and #update
actions. This is a running issue and Ryan promised a solution for cancan-2 (seems to be abandonned for cancan-1).
Anyway, you can use the code in this PR to make cancan compatible with strong parameters. Here it is extracted in a monkey patch. I prefer to use monkey patches rather than pointing gem to specific commit or fork so that I don't lose any master gem update.
Reading again the doc, I've found an other way to avoid strong parameter problem. You can overload loader if you use a before_filter before #load_resource.
There are several implications :
#new
, #show
, #create
, etc (may use several conditional filters)This defeats the simplicity of cancan resource loading, and serves the sole purpose of letting cancan know what the resource is when you want to use a block with #can
and #cannot
.
I would still rather go with the monkey patch, so that you don't end up with a lot of useless code in your controllers when issue is fixed upstream.
Upvotes: 1