Pundit::Before
Adds before hook to pundit policy classes to resolve things like varvet/pundit#474. Inspired by action_policy
pre-checks.
Installation
Add this line to your application's Gemfile:
gem "pundit-before"
And then execute:
bundle install
Usage
Use allow! inside callback method or block to return true without evaluating edit? method defined in policy.
class UserPolicy < ApplicationPolicy
include Pundit::Before
before :check_admin
def edit?
false
end
private
def check_admin
allow! if user.admin?
end
end
UserPolicy.new(User.new(admin: true), record).edit? # => true
UserPolicy.new(User.new(admin: false), record).edit? # => false
Use deny! inside callback method or block to return false without evaluating edit? method defined in policy.
class UserPolicy < ApplicationPolicy
include Pundit::Before
before :check_admin
def edit?
true
end
private
def check_admin
deny! unless user.admin?
end
end
UserPolicy.new(User.new(admin: true), record).edit? # => true
UserPolicy.new(User.new(admin: false), record).edit? # => false
Internally before hook is implemented as ActiveSupport::Callbacks, so the callback chain will halt if do any call to
allow! or deny! method. It's similar as Rails controller action filters works.
block form
class UserPolicy < ApplicationPolicy
include Pundit::Before
before do
allow! if user.admin?
end
def edit?
false
end
end
skip before hook
class UserPolicy < ApplicationPolicy
include Pundit::Before
before :check_admin
def edit?
false
end
private
def check_admin
allow! if user.admin?
end
end
class OperatorPolicy < UserPolicy
skip_before :check_admin
end
UserPolicy.new(User.new(admin: true), record).edit? # => true
OperatorPolicy.new(User.new(admin: true), record).edit? # => false
using only modifier
class UserPolicy < ApplicationPolicy
include Pundit::Before
before :check_admin, only: :update?
def edit?
false
end
private
def check_admin
allow! if user.admin?
end
end
UserPolicy.new(User.new(admin: true), record).edit? # => false
using except modifier
class UserPolicy < ApplicationPolicy
include Pundit::Before
before :check_admin, except: :edit?
def edit?
false
end
def destroy?
false
end
private
def check_admin
allow! if user.admin?
end
end
UserPolicy.new(User.new(admin: true), record).edit? # => false
UserPolicy.new(User.new(admin: true), record).destroy? # => true
calling multiple methods
class UserPolicy < BasePolicy
before :check_presence, :check_admin
def edit?
false
end
private
def check_presence
deny! unless user.present?
end
def check_admin
allow! if user.admin?
end
end
UserPolicy.new(nil, record).edit? # => false
UserPolicy.new(User.new(admin: false), record).edit? # => false
UserPolicy.new(User.new(admin: true), record).edit? # => true
Development
After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests.
You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bin/rake install.
To release a new version, update the version number in version.rb, and then run bin/rake release,
which will create a git tag for the version, push git commits and the created tag, and push the .gem file to
rubygems.org.
License
Copyright © 2023 Javier Aranda. Released under the terms of the MIT license.