sajad torkamani

Install gem

./bin/bundle add pundit

Configure Pundit

Include the Pundit module in ApplicationController.

class ApplicationController < ActionController::Base
  include Pundit::Authorization
end

Generate default application policy

./bin/rails g pundit:install

This will create a new file: app/policies/application_policy.rb.

Restart Rails server.

Add policy

You typically create a policy for each model in your app. For example, supposing you have a Post mode, you’ll want to create a PostPolicy at app/policies/post_policy.

./bin/rails g pundit:policy Post
class PostPolicy
  attr_reader :user, :post

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

  def update?
    user.admin? || !post.published?
  end
end

Use policy to authorize action

In a controller, you can do something like:

def update
  @post = Post.find(params[:id])
  authorize @post
  if @post.update(post_params)
    redirect_to @post
  else
    render :edit
  end
end

Thanks to naming conventions, Pundit will take the authorize @post invocation and do something like this:

unless PostPolicy.new(current_user, @post).update?
  raise Pundit::NotAuthorizedError, "not allowed to update? this #{@post.inspect}"
end

(Bonus) Add a owner? method

You often need to only grant permission if a user owns a resource. To keep things DRY, consider adding a owner? method to the base ApplicationPolicy (app/policies/application_policy.rb).

class ApplicationPolicy
  attr_reader :user, :record

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

  ## other methods

  def owner?
    user.id === record.user_id
  end
end

Now, you can just reuse this method in each model policy. For example, suppose you have QuotePolicy.

# frozen_string_literal: true

class QuotePolicy < ApplicationPolicy
  def edit?
    owner?
  end

  def update?
    owner?
  end

  # And so on...
end

Sources

Leave a comment

Your email address will not be published. Required fields are marked *