Mastering Authorization in Rails with Pundit Gem

Mastering Authorization in Rails with Pundit Gem

Authorization is a critical component of any web application, ensuring that users can only access resources they are permitted to. Pundit is a popular authorization library for Ruby on Rails that allows developers to define fine-grained access rules. This article will guide you through using the Pundit gem for authorization in a Rails application, complete with an example.

Step-by-Step Guide 

1. Adding Pundit to Your Rails Application

First, add Pundit to your Gemfile and run bundle install:

gem 'pundit'


bundle install

Next, generate the Pundit installation files:

rails generate pundit:install

This will create an application_policy.rb file in the app/policies directory, which serves as the default policy for all models.

2. Defining Policies
Policies in Pundit are Plain Old Ruby Objects (POROs) that encapsulate the authorization logic. Each policy corresponds to a model in your application. Let’s consider a simple example where we have a Post model and we want to define authorization rules for it.

Create a policy for the Post model:

rails generate pundit:policy post

This generates a post_policy.rb file in the app/policies directory.

3. Implementing Authorization Logic
Open the post_policy.rb file and define the authorization rules:

class PostPolicy < ApplicationPolicy
  def index?
    true
  end

  def show?
    true
  end

  def create?
    user.present?
  end

  def update?
    user.present? && user == record.user
  end

  def destroy?
    user.present? && user == record.user
  end
end

Here, we define methods corresponding to each action (index?, show?, create?, update?, and destroy?). These methods return true or false based on the user and the record being accessed.

4. Using Policies in Controllers
In your controllers, you can use Pundit to authorize actions. First, include the Pundit module in the ApplicationController:

class ApplicationController < ActionController::Base
include Pundit
end

Then, use the authorize method to check authorization in your PostsController:

class PostsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  def index
    @posts = Post.all
    authorize @posts
  end

  def show
  end

  def new
    @post = Post.new
    authorize @post
  end

  def create
    @post = current_user.posts.build(post_params)
    authorize @post
    if @post.save
      redirect_to @post, notice: 'Post was successfully created.'
    else
      render :new
    end
  end

  def edit
    authorize @post
  end

  def update
    authorize @post
    if @post.update(post_params)
      redirect_to @post, notice: 'Post was successfully updated.'
    else
      render :edit
    end
  end

  def destroy
    authorize @post
    @post.destroy
    redirect_to posts_url, notice: 'Post was successfully destroyed.'
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:title, :body)
  end
end

In this controller, we use authorize to check permissions before performing any actions.

5. Handling Unauthorized Access
Pundit raises a Pundit::NotAuthorizedError if a user is not authorized to perform an action. You can handle this error globally in the ApplicationController:

class ApplicationController < ActionController::Base
  include Pundit

  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  private

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

This way, if a user tries to perform an unauthorized action, they will be redirected with an error message.

Conclusion

Using Pundit for authorization in Rails is a powerful and flexible way to control access to resources in your application. By defining policies and using them in your controllers, you can ensure that users can only perform actions they are authorized for. This covered the basics, but Pundit also supports more complex scenarios, including scopes and custom policy generators.

For more detailed information, check out the Pundit GitHub repository

Related Posts

Leave a Comment

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

en_USEnglish