Setup Pundit in Rails
Install gem
./bin/bundle add pundit
Configure Pundit
Include the Pundit
module in ApplicationController
.
class ApplicationController < ActionController::Base
include Pundit::Authorization
end
Generate default application policy
./bin/rails g pundit:install
This will create a new file: app/policies/application_policy.rb
.
Restart Rails server.
Add policy
You typically create a policy for each model in your app. For example, supposing you have a Post
mode, you’ll want to create a PostPolicy
at app/policies/post_policy
.
./bin/rails g pundit:policy Post
class PostPolicy
attr_reader :user, :post
def initialize(user, post)
@user = user
@post = post
end
def update?
user.admin? || !post.published?
end
end
In a controller, you can do something like:
def update
@post = Post.find(params[:id])
authorize @post
if @post.update(post_params)
redirect_to @post
else
render :edit
end
end
Thanks to naming conventions, Pundit will take the authorize @post
invocation and do something like this:
unless PostPolicy.new(current_user, @post).update?
raise Pundit::NotAuthorizedError, "not allowed to update? this #{@post.inspect}"
end
(Bonus) Add a owner?
method
You often need to only grant permission if a user owns a resource. To keep things DRY, consider adding a owner?
method to the base ApplicationPolicy
(app/policies/application_policy.rb
).
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
## other methods
def owner?
user.id === record.user_id
end
end
Now, you can just reuse this method in each model policy. For example, suppose you have QuotePolicy
.
# frozen_string_literal: true
class QuotePolicy < ApplicationPolicy
def edit?
owner?
end
def update?
owner?
end
# And so on...
end
Sources
Thanks for your comment 🙏. Once it's approved, it will appear here.
Leave a comment