12
votes

In my project, i have pretty common namespace "admin".

namespace :admin do
    resources :users, except: :show
end

I use Pundit gem to set proper authorization, but i found it difficult to use with controllers within namespace. my policies are organised as below

-policies
    -admin
        user_policy.rb
    application_policy.rb
    admin_policy.rb
    awesome_policy.rb

very similar to controllers.

However, when inside the controller i use "authorize" method i get nothing but an error, informing that app is "unable to find UserPolicy". My UserPolicy looks like this:

class Admin::UserPolicy < AdminPolicy
end

So what is the problem, what should I do to make Pundit see those policies inside namespace?

4

4 Answers

4
votes

With the new merged commit you can do this.

It will work automatically.

UPDATE:

From 0.3 version is effectively removed without replacing feature. However namespace feature can be obtained in namespace branch on github.

You can see the discussion of feature in issue on github.

My suggestion for people who want use namespaces with pundit - don't use yet. Make before filter to access restricted area like admin dashboard and leave authorization model rules in pundit files. That's way you will be able to use pundit without hacks and problems.

3
votes

Short answer: you can't make Pundit use controller namespace-specific policies.

Long answer: Pundit looks at the resource (model) to determine which Policy class to use, so any time you pass an instance of the User model in as the resource, it's going to look for UserPolicy, not Admin::UserPolicy

See here, here and here.

You could specify a policy class on your User model, but this doesn't really solve your namespaced controller issue since Pundit is going to derive the policy class from the model, regardless of where you're authorizing.

2
votes

While onemanstartup mentioned that is should work automatically now, I wasn't able to get the namespaced policy to work, but here's what I did find to be acceptable.

In your case, in the AdminPolicy, I added custom action names, like

def new_user?
  some code
end

and then in my Admin::UserController#new action

def new
  authorize @user, :new_user?
end
1
votes

Just came here because of the same problem. Working with pundit v2.1.0, this is possible by overriding policy_scope and authorize in the controller. What I did for a similar setup:

module Admin
  class ModuleController < ModuleController
    private

    def policy_scope(scope)
      super([:admin, scope])
    end

    def authorize(record, query = nil)
      super([:admin, record], query)
    end
  end
end

And then just use the usual ways of working with your policy in your controller, which will then take the policy from your Admin namespace.

This is also described in the README at https://github.com/varvet/pundit#policy-namespacing

In case you need more context than just the current user and the record, Pundit policies with two input parameters will be helpful.