Reputation: 7590
I am trying to understand a bit better the capabilities of CanCan when it comes to authorization. Imagine this controller action:
def update
if can? :action, Model or can? :resolve, Model or can? :authorize, AnotherModel
# My Code here
respond_with @model
else
raise CanCan::AccessDenied.new(nil, :update, Model)
end
end
I got to this point while trying to find a solution to the above using authorize!
. As far as I can see (also looking at the signature) authorize!
only accepts one permission (action) and one subject, with an optional message, like this:
def authorize!(action, subject, *args)
# code
end
Is there a way which I may be overlooking to instruct authorize to check for multiple actions? Putting two authorize one after the other will act as an AND
condition between permissions, what I would like is it to work like an OR
condition, basically similar to the custom code above (which has the problem of raising the AuthorizationNotPerformed
in CanCan, avoidable with skip_authorize_resource
which is not something I would really like to do).
Upvotes: 3
Views: 2706
Reputation: 7590
In the end I added this rather nice solution to the ability class:
def multi_authorize!(*actions, message_hash)
message = nil
if message_hash.kind_of?(Hash) && message_hash.has_key?(:message)
message = message_hash[:message]
end
auth = false
actions.each do |act|
auth = auth || can?(act[0], act[1])
end
if !auth
message ||= unauthorized_message(actions[0][0], actions[0][1])
raise CanCan::AccessDenied.new(message, actions[0][0], actions[0][1])
end
end
Included an helper for the Controllers:
module CanCanAddition
def multi_authorize!(*args)
@_authorized = true
current_ability.multi_authorize!(*args)
end
end
if defined? ActionController::Base
ActionController::Base.class_eval do
include ApplicationHelper::CanCanAddition
end
end
Which I call like this:
def create
multi_authorize! [:create, Model1], [:authorize, Model2], :message => "You are not authorized to perform this action!"
# other code...
end
WARNING: Due to the code in the ability class, you must provide a message or the last pair of authorization will not be passed in the *args
. I'll take some time to overcome this but the idea of the solution I think fits nice with.
Upvotes: 3
Reputation: 1934
You can create an custom action and create as many or
-conditions as you like.
can :my_update_action, Project do |project|
can?(:read, ModelX) || can?(:read, ModelY) || ...
end
Upvotes: 3