2023-05-30 - Authorization with Pundit


main topics


Pundit checklist

Steps explained

bundle add pundit
rails generate pundit:install
# creates the 'app/policies/applicatoin_policy.rb'

stuff to paste in app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  before_action :authenticate_user!
  include Pundit::Authorization

  # Pundit: allow-list approach
  after_action :verify_authorized, except: :index, unless: :skip_pundit?
  after_action :verify_policy_scoped, only: :index, unless: :skip_pundit?

  # Uncomment when you *really understand* Pundit!
  # rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
  # def user_not_authorized
  #   flash[:alert] = "You are not authorized to perform this action."
  #   redirect_to(root_path)
  # end

  private

  def skip_pundit?
    devise_controller? || params[:controller] =~ /(^(rails_)?admin)|(^pages$)/
  end
end

Run rails server and try to acces an "#index" action.

You should see Pundit::PolicyScopingNotPerformedError (if you see uninitialized constant ApplicatoinController::Pundit, you need to bundle && rails s).

rails generate pundit:policy collective
# generates 'app/policies/collective_policy.rb'

app/policies/collective_policy.rb

class CollectivePolicy < ApplicationPolicy
  class Scope < Scope
  end

  def show?
    true
  end
end

In the Controller, add the authorize line. Example

def show
  authorize @restaurant
end

Do the same for new and create.

For edit, update and destroy, only allow the person who created the resource.

app/policies/restaurant_policy.rb

def edit?
  update?
end

def update?
  record.user == user
  # in my model it was collective.owner
end

def destroy?
  record.user == user
end