Implementing Fine-Grained Access Control in Rails Using Rolify and Pundit

Implementing fine-grained access control in a Ruby on Rails application is essential for maintaining security and ensuring users have appropriate permissions. Combining the power of Rolify and Pundit allows developers to create flexible and scalable authorization systems.

Understanding Rolify and Pundit

Rolify is a role management library that simplifies assigning and managing roles for users. Pundit is an authorization library that provides a simple way to define policies for different actions based on user roles and other attributes.

Setting Up Rolify

Start by adding Rolify to your Gemfile:

gem 'rolify'

Run the bundle command:

bundle install

Generate the Rolify configuration and migration:

rails generate rolify Role User

Run the migration:

rails db:migrate

Assigning Roles to Users

In your user model, include Rolify:

class User < ApplicationRecord

rolify

Assign roles to users:

user.add_role :admin

Configuring Pundit

Add Pundit to your Gemfile:

gem 'pundit'

Run bundle install:

bundle install

Include Pundit in your ApplicationController:

class ApplicationController < ActionController::Base

include Pundit

Set up a rescue for unauthorized access:

rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

Define the method:

private

def user_not_authorized

redirect_to(request.referrer || root_path)

flash[:alert] = “You are not authorized to perform this action.”

Creating Policies

Generate a policy for a resource, e.g., Post:

rails generate pundit:policy Post

Edit the generated policy to include role checks:

class PostPolicy

attr_reader :user, :post

def initialize(user, post)

@user = user

@post = post

end

Add permission methods:

def update?

user.has_role?(:admin) || (user.has_role?(:editor) && post.author_id == user.id)

Similarly, define other actions like show?, destroy?, etc.

Implementing Authorization in Controllers

Use Pundit’s authorize method in your controller actions:

def update

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

authorize @post

Proceed with update if authorized:

if @post.update(post_params)

redirect_to @post, notice: "Post updated successfully."

Otherwise, Pundit’s rescue will handle unauthorized access.

Conclusion

Integrating Rolify and Pundit provides a robust framework for implementing fine-grained access control in Rails applications. By managing roles with Rolify and defining permissions with Pundit policies, developers can create secure and flexible authorization systems tailored to their application’s needs.