top of page

How I did my project Authorization with Pundit.

  • Writer: Arthur Sukhinin
    Arthur Sukhinin
  • Nov 17, 2021
  • 3 min read

Web applications involving user management has two parts to it, which is authentication and authorization. And you don't get to authorization without authentication, as we can't determine what you can do unless we know who you are in the first place.


Pundit is a user authentication jam. As the developer points out: Pundit provides a set of helpers to help you use regular Ruby classes and object-oriented design patterns to create a simple, reliable, and scalable authorization system. Of course, there are many alternative solutions, but in my project I decided to use Pundit, because it is a fairly functional and optimal solution. Next, I'll show you how I did it.




How it works?

Pundit helps us to define policies which are PORC - Plain Old Ruby Classes - which means that the class does not inherit from other classes nor include in other modules from the framework. Thus makes it very easy to understand the code.


You create a Policy class that deals with authorizing access to a specific type of record. The class has the same name as some kind of model class, only suffixed with the word "Policy". The first argument is a user. In your controller, Pundit will call the current_user method to retrieve what to send into this argument. Make sure you have that method in your app. The second argument is some kind of model object, whose authorization you want to check. This does not need to be an ActiveRecord or even an ActiveModel object, it can be anything really.


#1: Installation

Pundit's installation is pretty standard.


Add a line for it in your Gemfile:

gem "pundit"

Next you can run the generator, which will add application policy:


rails g pundit:install

It will generated app/policies/ dirrectory.


In my case:


class ApplicationPolicy attr_reader :user, :record def initialize(user, record) @user = user || GuestUser.new @record = record end def index? true end def show? false end def create? false end def new? create? end def update? false end def edit? update? end def destroy? false end class Scope def initialize(user, scope) @user = user @scope = scope end def resolve scope.all end private attr_reader :user, :scope end end


Next step creating app/controllers/concerns/authorization.rb


module Authorization extend ActiveSuport::Concern included do include Pundit rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized private def user_not_authorized flash[:danger] = 'You are not authorized for this action!' redirect_to(request.referer || root_path) end end end

Here we create a method to track the Pundit::NotAuthorizedError and display a message that the user is not authorized.

Don't forget add include Authentication to your ApplicationController



#2: Creating Policies.


You can generate new policy by

rails g pundit:policy post

or you can create it manually.


In my case:


class ArticlePolicy < ApplicationPolicy def index? true end def show? true end def create? !user.guest? end def new? create? end def update? user.admin_role? || user.moderator_role? || user.author?(record) end def edit? update? end def destroy? user.admin_role? || user.author?(record) end end



Here you can allow access for any methods and users. In my case I use



class ArticlesController < ApplicationController before_action :authorize_article! after_action :verify_authorized

---------------

-------------- private

def authorize_article! authorize(@article || Article) end end


For user.admin_role? I use the enum method: class User < ApplicationRecord enum role: { basic: 0, moderator: 1, admin: 2 }, _suffix: :role

The authorize method (in this case (authorize(@article || Article)) automatically infers that Article will have a matching ArticlePolicy class, and instantiates this class, handing in the current user and the given record. It then infers from the action name, that it should call.


In conclusion, I want to say that I really liked using Pundit. It's a fairly concise app, easy to customize, and works really well. I recommend it to anyone who hasn't tried it yet.










 
 
 

Comments


  • Facebook
  • Twitter
  • LinkedIn

©2021 by Arthur Sukhinin blog. Proudly created with Wix.com

Subscribe Form

Thanks for submitting!

bottom of page