ruby-on-railsdevisepundit

Pundit::AuthorizationNotPerformedError with Devise controller


I am fairly new to using this Pundit gem but seem to be having trouble understanding the policy system. I have added checks that Pundit has been called for authorization (verify_authorized) and for scoping (verfify_policy_scoped). However, this causes errors when I visit the Devise sessions controller.

Application Controller

class ApplicationController < ActionController::Base
  include Pundit
  protect_from_forgery
  before_filter :authenticate_person!

  # Verify that controller actions are authorized. Optional, but good.
  after_filter :verify_authorized,  except: :index
  after_filter :verify_policy_scoped, only: :index


  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  private

  def pundit_user
    Person.find_by_id(current_person)
  end

  def user_not_authorized
    flash[:alert] = "You are not authorized to perform this action."
    # redirect_to(request.referrer || root_path)
  end
end

Application Policy

class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    raise Pundit::NotAuthorizedError, "must be logged in" unless user
    @user = user
    @record = record
  end

  def index?
    false
  end

  def show?
    scope.where(:id => record.id).exists?
  end

  def create?
    false
  end

  def new?
    create?
  end

  def update?
    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

  def scope
    Pundit.policy_scope!(user, record.class)
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      scope
    end
  end
end

Error Messages

Pundit::AuthorizationNotPerformedError in
  Devise::SessionsController#new

Pundit::PolicyScopingNotPerformedError in
  ...

Solution

  • You probably need to check this section from Pundit's readme.

    It basically says, that when using verify_authorized is used in after_action, it will check if authorized was actually called.

    Pundit adds a method called verify_authorized to your controllers. This method will raise an exception if authorize has not yet been called. You should run this method in an after_action to ensure that you haven't forgotten to authorize the action.

    The same is true for verify_policy_scoped, but for policy_scope:

    Likewise, Pundit also adds verify_policy_scoped to your controller. This will raise an exception in the vein of verify_authorized. However, it tracks if policy_scope is used instead of authorize. This is mostly useful for controller actions like index which find collections with a scope and don't authorize individual instances.

    In your case exception is caused by the fact that you didn't called authorize in Devise::SessionsController#new action.

    I think, the best way to deal with it, is to remove after_action checks from ApplicationController and move them to a subclass.