authorization-pundit
SKILL.md
Authorization with Pundit for Rails 8
Overview
Pundit provides policy-based authorization:
- Plain Ruby policy objects
- Convention over configuration
- Easy to test
- Scoped queries for collections
- Works with any authentication system
Quick Start
# Add to Gemfile
bundle add pundit
# Generate base files
bin/rails generate pundit:install
# Generate policy for model
bin/rails generate pundit:policy Event
Project Structure
app/
├── policies/
│ ├── application_policy.rb # Base policy
│ ├── event_policy.rb
│ ├── vendor_policy.rb
│ └── user_policy.rb
spec/policies/
├── event_policy_spec.rb
├── vendor_policy_spec.rb
└── user_policy_spec.rb
TDD Workflow
Authorization Progress:
- [ ] Step 1: Write policy spec (RED)
- [ ] Step 2: Run spec (fails)
- [ ] Step 3: Implement policy
- [ ] Step 4: Run spec (GREEN)
- [ ] Step 5: Add policy to controller
- [ ] Step 6: Test integration
Base Policy
# app/policies/application_policy.rb
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
# Default: deny all
def index?
false
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
raise NotImplementedError, "Define #resolve in #{self.class}"
end
private
attr_reader :user, :scope
end
end
Policy Implementation
Four policy patterns are available. See policies.md for full implementations:
- Basic Policy – owner-based access with
Scopefiltering byaccount_id - Role-Based Policy – combines
owner?,admin?,member_or_above?predicates; admin sees all in Scope - Policy with State Conditions – gate actions on record state (
locked?,destroyable?,can_cancel?) - Headless Policy – policy not tied to a record (dashboards, admin panels)
Also in policies.md:
- Permitted Attributes – role-based
permitted_attributesfor strong params - Nested Resource Policies – delegate to parent resource policy (
EventPolicy.new(user, record.event).show?)
Controller Integration
See controller-integration.md for full examples of:
ApplicationControllersetup withinclude Pundit::Authorization,after_action :verify_authorized, andrescue_from Pundit::NotAuthorizedError- Full CRUD controller using
authorize @eventandpolicy_scope(Event) - Custom action authorization:
authorize @event, :publish? - Skipping authorization for public pages with
skip_after_action
View Integration
See views-and-testing.md for:
- ERB conditional rendering with
policy(@event).edit? - ViewComponent integration with
EventPolicy.new(@user, @event)
Testing
See views-and-testing.md for:
- Policy spec with
permissions :show?blocks andpermit/not_to permitmatchers pundit-matchersgem usage withpermit_actions/forbid_actions- Request spec testing HTTP status and redirect behavior
- I18n error message configuration and custom
rescue_fromhandler
Checklist
- Policy spec written first (RED)
- Policy inherits from ApplicationPolicy
- Scope defined for collections
- Controller uses
authorizeandpolicy_scope -
verify_authorizedafter_action enabled - Views use
policy(@record).action? - Error handling configured
- Multi-tenancy enforced in Scope
- All specs GREEN
References
- policies.md – Policy patterns: basic, role-based, state conditions, headless, nested, permitted attributes
- controller-integration.md – ApplicationController setup, CRUD, custom actions, skip authorization
- views-and-testing.md – ERB views, ViewComponent, policy specs, pundit-matchers, request specs, I18n errors
Weekly Installs
19
Repository
thibautbaissac/…i_agentsGitHub Stars
421
First Seen
Jan 24, 2026
Security Audits
Installed on
opencode14
codex12
claude-code11
github-copilot10
gemini-cli10
cursor10