AccessForge
AccessForge is a controller-oriented authorization engine with composable rule objects for Ruby on Rails.
It provides:
- Convention-based policy resolution
- Action-oriented authorization methods
- Composable, reusable policy rules
- A clean extension surface for custom authorization strategies
AccessForge treats authorization as an application concern at the controller boundary — explicit, testable, and decoupled from persistence.
Why AccessForge?
AccessForge is designed around three principles:
- Authorization decisions occur at the controller boundary.
- Authorization should be explicit per action.
- Authorization logic should be reusable and composable.
Rather than embedding complex logic directly inside policy methods, AccessForge encourages the use of Policy Rule classes — small, focused, testable units of authorization behavior.
This keeps policies readable while allowing authorization strategies to evolve independently.
Design Philosophy
AccessForge separates policy orchestration from authorization strategy.
It does not impose a persistence model or assume how permissions are stored. Instead, it provides a composable rule system that allows you to implement your own authorization strategy.
Authorization strategies such as group-based RBAC can be implemented via extension gems without modifying your policies.
Policies remain stable. Strategies remain replaceable.
Installation
Add this line to your application's Gemfile:
gem 'access_forge'
Then execute:
bundle install
Usage
Step 1: Enable policy resolution in your controllers
Include AccessForge::ControllerHelpers to enable convention-based policy resolution:
class ApplicationController < ActionController::API
include AccessForge::ControllerHelpers
end
Step 2: Register the authorization hook
Register the authorize_user! hook to enforce authorization before each action:
class ApplicationController < ActionController::API
include AccessForge::ControllerHelpers
before_action :authorize_user!
end
Step 3: Define your policy classes
AccessForge resolves policy classes using controller naming conventions.
For example:
EmployeesController→EmployeePolicy
Policies should inherit from AccessForge::Policy, either directly or via an application-level base policy.
class ApplicationPolicy < AccessForge::Policy
end
class EmployeePolicy < ApplicationPolicy
end
If you need to override the default resolution behavior, you may define #policy_class in your controller:
class EmployeesController < ApplicationController
def policy_class
DifferentPolicy
end
end
Step 4: Implement policy methods
For each controller action, AccessForge calls the corresponding predicate method on the policy.
For example:
show→show?create→create?
Each method should return true or false.
A false result will prevent the action from being performed and return a 401 response. A true result allows execution to proceed.
class EmployeePolicy < ApplicationPolicy
def index?
true
end
def create?
false
end
end
If multiple actions share identical logic, you may use:
can_read?forindexandshowcan_write?forcreate,update, anddestroy
class EmployeePolicy < ApplicationPolicy
def can_read?
true
end
def can_write?
false
end
end
Step 5: Extract reusable logic with Policy Rules
Up until now, authorization logic has lived directly inside policy methods.
For reusable or cross-cutting logic, AccessForge provides Policy Rules.
Policy Rules allow authorization behavior to be extracted, composed, and reused across policies without coupling policies to persistence or infrastructure concerns.
AccessForge::Policy exposes an authorized? helper:
(rules, = {})
rules— an array of Policy Rule classesoptions— optional parameters passed to each rule
If any rule returns true, authorization succeeds.
AccessForge includes two default rules:
OpenPolicyRule— always grants accessClosedPolicyRule— always denies access
module AccessForge
class OpenPolicyRule
def self.(_user, _controller, )
true
end
end
class ClosedPolicyRule
def self.(_user, _controller, )
false
end
end
end
You may define custom rules:
class PermissionPolicyRule
def self.(user, _controller, )
= "Can #{options[:verb]} #{options[:feature]}"
user..exists?({ permissions: { name: } })
end
end
class EmployeePolicy < ApplicationPolicy
def index?
(
[ PermissionPolicyRule ],
{ feature: 'Employees', verb: :read }
)
end
end
This approach keeps policy classes focused while allowing authorization strategies to scale independently.
Extensions
AccessForge is designed to be extended.
Official and third-party extensions may provide:
- Persistence-backed authorization strategies
- RBAC implementations
- Alternative rule sets
- Integration layers
Because policies depend only on rule interfaces, new strategies can be introduced without rewriting existing policies.
Development
After checking out the repository:
bin/setup
rake spec
To release a new version:
- Update the version number in
version.rb - Run:
bundle exec rake release
This will tag the release, push commits, and publish the gem to RubyGems.
Contributing
Bug reports and pull requests are welcome on GitHub:
https://github.com/CodeTectonics/access_forge.
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the AccessForge project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.