Table of Contents
Integrating Devise and Pundit in a Ruby on Rails application provides a robust solution for managing user authentication and authorization. Devise handles user sign-up, login, and password management, while Pundit offers a simple way to manage permissions and access control.
Why Use Devise and Pundit Together?
Using Devise and Pundit together streamlines the development process by separating concerns: Devise manages who the user is, and Pundit controls what the user can do. This separation enhances security, maintainability, and clarity in your codebase.
Setting Up Devise
First, add Devise to your Rails project. Include it in your Gemfile:
Gemfile
“`ruby gem ‘devise’ “`
Run bundle install and initialize Devise:
Terminal commands
“`bash bundle install rails generate devise:install rails generate devise User rails db:migrate “`
Configuring Pundit
Add Pundit to your Gemfile:
Gemfile
“`ruby gem ‘pundit’ “`
Run bundle install and include Pundit in your ApplicationController:
Terminal commands
“`bash bundle install “`
And in app/controllers/application_controller.rb:
Code snippet
“`ruby class ApplicationController < ActionController::Base include Pundit after_action :verify_authorized, except: :index, unless: :devise_controller? after_action :verify_policy_scoped, only: :index, unless: :devise_controller? 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 ```
Creating Policies with Pundit
Generate a policy for your models, for example, Post:
Command
“`bash rails generate pundit:policy Post “`
This creates app/policies/post_policy.rb. Define permissions within this file:
Example
“`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.author == user end def destroy? user.admin? end end “`
Using Devise and Pundit in Controllers
Ensure users are authenticated before accessing certain actions and authorize actions with Pundit:
Example
“`ruby class PostsController < ApplicationController before_action :authenticate_user! before_action :set_post, only: [:show, :edit, :update, :destroy] before_action :authorize_post, only: [:edit, :update, :destroy] def show authorize @post end def edit end def update if @post.update(post_params) redirect_to @post, notice: 'Post was successfully updated.' else render :edit end end def destroy @post.destroy redirect_to posts_url, notice: 'Post was successfully destroyed.' end private def set_post @post = Post.find(params[:id]) end def authorize_post authorize @post end def post_params params.require(:post).permit(:title, :content) end end ```
Best Practices and Tips
Always keep your policies up to date with your application’s requirements. Use scoped policies for different user roles and ensure that authorize calls are present in relevant controller actions.
Test your policies thoroughly to prevent unauthorized access. Consider using RSpec with pundit-matchers for effective testing.
Conclusion
Combining Devise and Pundit in your Rails application offers a comprehensive solution for secure user authentication and fine-grained authorization. Proper integration simplifies managing user permissions and enhances your app’s security posture.