Let's say I am using the Pundit gem for authorization. I have the following controller:
class BlogsController < ApplicationController
before_action :check_authorization
...
private
def check_authorization
authorize :blog
end
end
Pundit looks at the argument passed in, :blog
and thus infers there is a BlogPolicy
class. It then looks for the corresponding action name with a question mark, such as: BlogPolicy#index?
.
If I want to look up the authorization on a specific resource I would just do this for that check_authorization
method:
def check_authorization
authorize @blog
end
Again, no problem. Pundit looks at the class of the resource, Blog
, and then looks for the BlogPolicy
class.
BlogPolicy#show?
method and pass in that @blog
resource. Here is the issue: what do I do when I want to authorize on a specific controller name AND authorize on a specific resource, but that resource does not sync up with the controller name?
Example:
class SomeOtherBlogsController < ApplicationController
before_action :check_authorization
...
private
def check_authorization
authorize :some_other_blog, @blog
end
end
The above code doesn't work, but hopefully it shows what I am trying to do. Lets pretend this is happening on SomeOtherBlogsController#show
action.
SomeOtherBlogPolicy#show?
method,@blog
resource as well.Hopefully the issue is apparent. Since the resource class does not sync up with the controller name, It seems I am not able to do the above. So If I have the same resource used in various different controllers, I'm out of luck. I wouldn't be able to check authorization of the resource in those various controller contexts. Is this impossible to do with Pundit?
Update:
In the controller, I have also attempted to directly call the Policy method like so:
SomeOtherBlogPolicy.new(current_user, @blog).show?
However, calling that raised a Pundit::AuthorizationNotPerformedError
. So it appears that more happens in that authorize
method than just returning true
or false
.
You can manually specify the resource class for a model by:
class Blog
def self.policy_class
SomeOtherBlogPolicy
end
end
Unfortunately its not possible to specify the policy class from the controller when calling authorize
...
This was true when I originally wrote the answer. v2.00 added a policy_class
option to authorize:
authorize(@blog, policy_class: SomeOtherBlogPolicy)
So the workaround in my original answer is no longer needed.