0
0
RailsHow-ToBeginner · 4 min read

How to Use Pundit for Authorization in Ruby on Rails

Use Pundit in Ruby on Rails by creating policy classes that define authorization rules for your models, then call authorize in your controllers to enforce these rules. Include Pundit in your application controller and use policy methods like show? or update? to control access.
📐

Syntax

Pundit uses policy classes named after your models to define authorization rules. Each policy has methods ending with ? that return true or false to allow or deny actions. In controllers, you call authorize @record to check permissions.

  • Policy class: Defines who can do what.
  • authorize method: Checks permission in controller.
  • current_user: Passed automatically to policies.
ruby
class PostPolicy
  attr_reader :user, :post

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

  def show?
    true
  end

  def update?
    user.admin? || post.user_id == user.id
  end
end

# In controller
class PostsController < ApplicationController
  include Pundit

  def show
    @post = Post.find(params[:id])
    authorize @post
  end
end
💻

Example

This example shows a PostPolicy that allows anyone to view a post but only the post owner or an admin to update it. The controller uses authorize to enforce these rules before showing or updating a post.

ruby
class PostPolicy
  attr_reader :user, :post

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

  def show?
    true
  end

  def update?
    user.admin? || post.user_id == user.id
  end
end

class PostsController < ApplicationController
  include Pundit

  def show
    @post = Post.find(params[:id])
    authorize @post
    render plain: "Post content: #{@post.content}"
  end

  def update
    @post = Post.find(params[:id])
    authorize @post
    if @post.update(post_params)
      render plain: "Post updated"
    else
      render plain: "Update failed", status: :unprocessable_entity
    end
  end

  private

  def post_params
    params.require(:post).permit(:content)
  end
end
Output
Post content: Hello World Post updated
⚠️

Common Pitfalls

Common mistakes include forgetting to include Pundit in your controller, not calling authorize for actions, or not defining policy methods correctly. Also, ensure current_user is available and policies handle nil users if needed.

Another pitfall is not rescuing Pundit::NotAuthorizedError to handle unauthorized access gracefully.

ruby
class PostsController < ApplicationController
  include Pundit

  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  def show
    @post = Post.find(params[:id])
    authorize @post  # Must call authorize or no check happens
  end

  private

  def user_not_authorized
    render plain: "You are not allowed to do this", status: :forbidden
  end
end
📊

Quick Reference

  • Include Pundit: include Pundit in ApplicationController.
  • Create Policy: rails g pundit:policy ModelName to generate.
  • Define Methods: Use def action? returning true/false.
  • Authorize: Call authorize @record in controller actions.
  • Handle Errors: Rescue Pundit::NotAuthorizedError for user feedback.

Key Takeaways

Always create a policy class for each model to define authorization rules clearly.
Use the authorize method in controllers to enforce these rules before performing actions.
Include Pundit in your ApplicationController to access its helper methods.
Handle Pundit::NotAuthorizedError to provide user-friendly error messages.
Test policies to ensure only allowed users can perform sensitive actions.