3

I have a Project policy that only super or admin can have access to.
It looks like this now:

class ProjectPolicy < ApplicationPolicy

  def index?
    super_or_admin?
  end

  def new?
    super_or_admin?
  end

  def create?
    super_or_admin?
  end

  def update?
    super_or_admin?
  end

  def show?
    super_or_admin?
  end

  def super_or_admin?
    user.role.name == 'superadmin' or user.role.name == 'admin'
  end
end

Is it possible to have pundit automatically apply super_or_admin? to all the routes instead of defining each of them manually?

resting
  • 16,287
  • 16
  • 59
  • 90
  • Not sure about Pundit, but if all those methods are doing is just calling `super_or_admin?` you could just alias them all: `alias :index? :super_or_admin?` and reduce some code that way – Simple Lime Aug 19 '17 at 06:43

1 Answers1

3

You can define your policy like this:

class ProjectPolicy < ApplicationPolicy
  def initialize(user, record)
    raise Pundit::NotAuthorizedError.new(policy: 'project') unless super_or_admin?
  end

  def method_missing(name, *args)
    true
  end

  def super_or_admin?
    user.role.name == 'superadmin' or user.role.name == 'admin'
  end
end

So it will check permissions on initialization. Defining method_missing in this case is necessary, because otherwise you will receive NoMethodError for action-specific methods (create?, update?, etc.). But you don't need to define them, because you check permissions in initialize method, that will be called anyway.

Then, if you need authorization in all actions, in your controller or it's ancestor you can define:

include Pundit

def authorize_project
  authorize :project
end

And use before_action callback like this:

before_action :authorize_project
Maksim Kalmykov
  • 1,293
  • 3
  • 20
  • 26