Modules in Pundit - How to organize policies ?

Here at Drawbotics, we use the Pundit gem for anything authorization-related.

Our platform has a client-side and an admin-side, both sharing the same database, models, and policies, which led to the following situation :

def new?  
    user.role == ClientUser::Owner || user.role == AdminUser::Supervisor
end  

Some refactoring was needed. We needed a way to :

  • Categorize the policies in folders in order to facilitate comprehension and navigation
  • Have different policies for shared models that can be called independently depending on where we are on the platform.

After some testing and diving into the Pundit codebase, we found a way to cover our 2 needs.

I implemented all the models with the following method :

def self.policy_class  
    Default::ModelPolicy
end  

Everytime i call the authorize method on a Model object, Pundit will call model.policy_class in order to find the policy class to use. That first change allowed us to easily categorize our policy classes in namespaces.

One problem remained : specifying the policy to use for a shared object.

In order to also have that feature, I added to every shared model an attr_writer also called policy_class and changed the policy_class method :

def policy_class(klass = Default::ModelPolicy)  
    @policy_class ||= klass
end  

With that change, I know have two choices when using Pundit :

  • I simply call authorize(model) (Pundit usual behavior)
authorize model  

This code will use the Default::ModelPolicy located in policies/default

  • I specify the policy before authorizing.
model.policy_class = Admin::ModelPolicy  
authorize model  

This code will use the Admin::ModelPolicy located in policies/admin. That way I can specify the policy to use for shared models.

With that solution, i've been able to clearly organize all policies before making all my changes.