Skip to content
Menu
Railshero
  • Blog
  • About Me
  • Contact Me
  • Privacy Policy
Railshero
Authorization With Pundit

Authorization With Pundit

Posted on September 8, 2021September 8, 2021 by Rails Hero

What is Authorization ?

Authorization is a method to permit or restrict different users or user groups by assigning them with different user access levels or privileges. This can be done by assigning every user or group of users with different access levels or user roles, roles such as admin, editor, subscriber, end user, etc. For example; Suppose i have a blogging application, i have set three user roles i.e admin, editor & subscriber. So, in this app the admin can have access to everything. The editors can only add or edit posts, they cannot add or remove users or make any major changes to the app. And the subscribers can only read posts and add comments to the posts. Similarly, just like the example above, we can create different user roles and restrict or permit the users to perform only those tasks that they are granted.

user roles
user roles

Authentication Vs Authorization

Authorization is not the same as Authentication, new developers often get confused between those two terms. Authentication is a method to grant access to users by verifying the identity of the user with user credentials like username, email, password, etc. Whereas, Authorization is a method to restrict or permit users or group of users to perform only those tasks that they are granted, by assigning different user roles or access levels to the users or group of users.

authorization error
authorization error

The Pundit Gem

We can create our authorization methods from scratch. But, to make life easier, there is a rubygem called ‘pundit’ that works like a charm. The pundit gem is a policy based authorization system, which makes everything easier to implement. We can create different policies for different models and permit or restrict any user action based on the types of user roles.

Pundit Github: https://github.com/varvet/pundit

Pundit Docs: https://www.rubydoc.info/gems/pundit

policies
policies

Installing Pundit

To install pundit, Add pundit to your gemfile and run bundler.

#File: Gemfile
gem 'pundit'
bundle install

And then, install pundit using the generator

rails g pundit:install

User Roles

Pundit is now ready to use, But first we need to create different user roles, for that we have to create a new active record migration. Please note that: i have already created my user model using devise, if you don’t know how to use devise check out my tutorial on devise by clicking here

Now create a new active record migration, to add a user role, with column type(integer). And then migrate the database

rails g migration add_role_to_users role:integer
rails db:migrate
user-role
user-role

The User Model

In our users model, we have to initialize the user roles that we want to be assigned to users. For instance, i have added 4 user roles that can be assigned, i.e; :enduser[role 0], :editor [role 1], :admin[role 2], :superadmin[role 3]. And whenever a new user is added or signed up, the default role of :enduser will be assigned, which can be later changed by the admin.

#File: app/models/user.rb
class User < ApplicationRecord

   enum role: [:enduser, :editor, :admin, :superadmin]
   after_initialize :set_default_role, :if => :new_record?

   def set_default_role
      self.role ||= :enduser
   end

   devise :database_authenticatable, :registerable,
   :recoverable, :rememberable, :validatable

end

The Application Controller

In order for pundit to work, we have to include pundit in our application controller. Also, we have to add a private method, as you can see below; to raise a flash notice and redirect to the root path or any other path, if the user is not authorized. The messages can be customized later, if you want to.

#File: app/controllers/application_controller.rb
class ApplicationController < ActionController::Base

   include Pundit
   protect_from_forgery with: :exception
   rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

private
   def user_not_authorized
      flash[:notice] = "Sorry, You Are Not Authorized To Do This"
      redirect_to(request.referrer || root_path)
   end

end

The Controller

Now, in our posts controller, we can just add authorize Post inside any action, to authorize with pundit. For instance in the example below, i added authorize Post to my create action. So, this way whenever a user tries to create a new record, pundit will check for the user role, assigned to the user and only permit the user, if the user has an authorized permission to perform the action.

#File: app/controllers/posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: %i[ show edit update destroy ]

#....Other Methods...
#....Other Methods...
def create
   unless signed_in?
      redirect_to new_user_session_path
   else
      authorize Post
      @post = current_user.posts.new(post_params)
      respond_to do |format|
         if @post.save
            format.html { redirect_to @post, notice: "Post was successfully created." }
            format.json { render :show, status: :created, location: @post }
         else
            format.html { render :new, status: :unprocessable_entity }
            format.json { render json: @post.errors, status: :unprocessable_entity }
         end
      end
   end
end

#....Other Methods...
#....Other Methods...

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

   def post_params
      params.require(:post).permit(:title, :description, :post_data, :user_id)
   end
end

Just add authorize Post i.e; authorize [ModelName]to any action, where you want pundit to check for the authorization. Like this:;

def action_name
   authorize ModelName
#.....if authorized do this.....
#.....else do this......
end

Pundit Policies

So, as i said earlier, pundit is a policy based authorization system, which makes everything much easier. Because, we can make changes or add new authorization methods from one place. As you can see below, our post policy. Pundit checks if the current logged in user is admin? and if so, pundit allows the admin user to create?, update? or destroy? the path. Pundit’s policy files can be found in ‘app/policies/‘

#File: app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy

attr_reader :current_user, :post

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

def create?
@current_user.admin?
end

def update?
@current_user.admin?
end

def destroy?
@current_user.admin?
end

end

Changing User Roles

If the admin wanted to change the user role of any other user, it can be done with a number of ways. If the admin has access to the database or rails console, he/she can do it from there. Or, an admin panel can be constructed from scratch to perform such actions. Or if you wanted to make it quick and easy, you can use the ‘active admin’ gem.

Active Admin Gem: https://github.com/activeadmin/activeadmin

active admin
active admin
active admin edit user
active admin edit user

Final Thoughts

So, that was a tutorial on the basics of authorization with pundit, pundit can also be customized heavily to add your own authentication methods or features, please check pundit documentation on how to do it. Also, we can build our own authorization functionality from scratch, if we wanted to. There are also other authorization gems that we can use, to add such functionalities similar to pundit. With gems like cancancan, rolify, authority, etc. So, that’s all folks, have a nice day.

1 thought on “Authorization With Pundit”

  1. Pingback: Some Popular Gems For Your Rails Apps - Railshero

Leave a Reply Cancel reply

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

Tags

active record active storage assets assign to many associations attachment attachments authentication authorization avatar bootstrap cdn config database deploy deployments devise DRY environment variables file uploads Gemfile gems has_many helpers heroku index indexing initializer javascript pagination parameters postgres production public routes.rb ruby gem ruby gems search sendgrid server smtp stylesheets variants views voting

Recent Posts

  • Understanding the DRY Principle in Rails
  • Building Multi-tenant Applications with Rails
  • Rails Basics: Templating Engines
  • Deploying With Capistrano
  • Automated Testing in Rails

Archives

  • July 2023
  • June 2023
  • October 2021
  • September 2021
  • August 2021
  • July 2021

Categories

  • Active Record
  • Activity Logging
  • Apps
  • Assets
  • Attachments
  • Audio
  • Authentication
  • Authorization
  • Deployments
  • Error Pages
  • File Uploads
  • General
  • Heroku
  • Heroku
  • Pagination
  • Rails Basics
  • RubyGems
  • Search Engine Optimization
  • Search/Indexing
  • Testing
  • User Interface
  • Video
  • Views & Templating
  • Voting
  • Web Security
©2025 Railshero | Theme: Wordly by SuperbThemes
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept All”, you consent to the use of ALL the cookies. However, you may visit "Cookie Settings" to provide a controlled consent.
Cookie SettingsAccept All
Manage consent

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary
Always Enabled
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Non-necessary
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
SAVE & ACCEPT