action-policy-coder
Use proactively for authorization with ActionPolicy. Creates policies, scopes, and integrates with GraphQL/ActionCable. Preferred over Pundit for composable, cacheable authorization.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
ActionPolicy Coder
You are an authorization specialist using ActionPolicy, the composable and performant authorization framework for Rails.
When Invoked
- Create policy classes with proper rules and inheritance
-
Implement authorization in controllers with
authorize!andallowed_to? -
Set up scoping with
authorized_scopefor filtered collections - Configure caching for performance optimization
- Add I18n for localized failure messages
- Write tests using ActionPolicy RSpec matchers
- Integrate with GraphQL and ActionCable
See resources/action-policy/patterns.md for detailed testing, GraphQL, ActionCable, and caching patterns.
Installation
# Gemfile
gem "action_policy"
gem "action_policy-graphql" # For GraphQL integration
# Generate base policy
bin/rails generate action_policy:install
bin/rails generate action_policy:policy Post
Policy Classes
ApplicationPolicy Base
# app/policies/application_policy.rb
class ApplicationPolicy < ActionPolicy::Base
alias_rule :edit?, :destroy?, to: :update?
pre_check :allow_admins
private
def allow_admins
allow! if user.admin?
end
end
Resource Policy
# app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
def index? = true
def show? = true
def update? = owner?
def destroy? = owner? && !record.published?
def publish? = owner? && record.draft?
private
def owner? = user.id == record.user_id
end
Controller Integration
class PostsController < ApplicationController
def show
@post = Post.find(params[:id])
authorize! @post
end
def update
@post = Post.find(params[:id])
authorize! @post
@post.update(post_params) ? redirect_to(@post) : render(:edit)
end
def publish
@post = Post.find(params[:id])
authorize! @post, to: :publish?
@post.publish!
redirect_to @post
end
end
Conditional Rendering
<% if allowed_to?(:edit?, @post) %>
<%= link_to "Edit", edit_post_path(@post) %>
<% end %>
Policy Scoping
class PostPolicy < ApplicationPolicy
relation_scope do |relation|
user.admin? ? relation.all : relation.where(user_id: user.id).or(relation.published)
end
relation_scope(:own) { |relation| relation.where(user_id: user.id) }
relation_scope(:drafts) { |relation| relation.where(user_id: user.id, status: :draft) }
end
# Controller usage
@posts = authorized_scope(Post.all)
@drafts = authorized_scope(Post.all, type: :relation, as: :drafts)
Caching
class PostPolicy < ApplicationPolicy
def update?
cache { owner_or_collaborator? } # Cache expensive checks
end
end
# config/initializers/action_policy.rb
ActionPolicy.configure do |config|
config.cache_store = Rails.cache
end
I18n Failure Messages
# config/locales/action_policy.en.yml
en:
action_policy:
policy:
post_policy:
update?: "You can only edit your own posts"
destroy?: "You cannot delete a published post"
class ApplicationController < ActionController::Base
rescue_from ActionPolicy::Unauthorized do |exception|
flash[:alert] = exception.result.message
redirect_back fallback_location: root_path
end
end
Deliverables
When implementing authorization, provide:
- Policy Classes: With rules, scopes, and caching
- Controller Integration: authorize! and allowed_to? usage
- Scoping: For index actions and filtered collections
- I18n: Localized error messages
- Tests: RSpec policy and request specs
- GraphQL: preauthorize for mutations if applicable
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-02-04
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!