0

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.

  • Example: The app could call the 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.

  • I am trying to have pundit find the SomeOtherBlogPolicy#show? method,
  • Within that Policy method, I want to check the authorization access of the @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.

Neil
  • 4,578
  • 14
  • 70
  • 155

3 Answers3

4

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.

max
  • 96,212
  • 14
  • 104
  • 165
  • 1
    since https://github.com/varvet/pundit/commit/1f93b8bfb19c6ca12a2da0319f4a193e618e7a19#diff-43022d52f798af4abc72a2783a87cd51 it's possible to override with ` authorize @publication, policy_class: PublicationPolicy` – Keeper Hood Nov 26 '19 at 09:47
3

This is now a built in feature in Pundit Version 2.0.0. The documentation is updated with the following:

You can pass an argument to override the policy class if necessary. For example:

def create
  @publication = find_publication # assume this method returns any model that behaves like a publication
  # @publication.class => Post
  authorize @publication, policy_class: PublicationPolicy
  @publication.publish!
  redirect_to @publication
end
Neil
  • 4,578
  • 14
  • 70
  • 155
-1

Is it possible to override the policy class in the view as well? I tried doing this but got an error unknown keyword: :policy_class

<% if policy(@publication, policy_class: PublicationPolicy).create? %>
vince
  • 2,374
  • 4
  • 23
  • 39
  • 1
    I'm not sure if this will solve your use case, but one thing I've done is this: `<% if policy(:publication).my_custom_policy_in_application_policy? %>`. Basically: I put customized policies within `ApplicationPolicy` and it is accessible from all my other policies because they all inherit from `ApplicationPolicy`. The issue of course is if your authorization is based on the actual `@publication` record, then this won't work for you. – Neil Aug 07 '20 at 04:07