The actor/role/permission model explained, how it differs from a single
admin boolean column, and where a library like Argus::Trail sits versus
Pundit, CanCanCan, and rolify.
Role-based access control (RBAC) is an authorization model where permissions
aren't granted to individual users directly — they're granted to roles, and
users are assigned to one or more roles. Instead of asking "can Alice delete an invoice,"
RBAC asks "is Alice in a role that grants invoices#destroy," which is the same
question for every other user in that role too. That indirection is the entire point: change
what a role can do once, and every actor holding it changes with it — no per-user permission
rows to hunt down and update.
admin column?
A single admin: true/false flag is RBAC's degenerate case — exactly two roles,
"everything" and "nothing" — and it's genuinely fine for an app that only ever needs that
distinction. It stops working the moment you need a third tier: a support rep who can view
accounts but not refund them, a deploy-only operator who should never touch billing, a
read-only auditor. Each new case either grows a pile of booleans
(admin, can_refund, can_deploy, ...) scattered across
the users table, or pushes you toward an actual role model — at which point you're building
RBAC by hand anyway, just without the vocabulary for it yet.
User/
Account model, but the concept doesn't require that (an API key or a service
account can be an actor too)."manage_billing"), or something structural like a controller action
(admin/accounts#read). Argus::Trail supports both: plain named permissions for
one-off grants, and module-wise permissions
(module_name + action) generated straight from your routes — see
Module-wise permissions.
Pundit and CanCanCan solve a narrower problem than full RBAC: given a user and a record,
answer yes/no. Neither ships a persisted role or permission model — you write the
Ability/policy classes yourself, usually hardcoding which roles can do what
directly in Ruby. That's a perfectly reasonable choice for an app with two or three fixed
roles that rarely change. It gets harder to manage once non-engineers need to create new roles
or tweak permissions without a deploy — at that point the role/permission data needs to live in
the database, with an admin UI on top, which is what Argus::Trail adds. It auto-integrates with
Pundit rather than replacing it: define a policy, or don't, and the admin screens default to
"any signed-in actor" either way.
| Capability | Argus::Trail | Pundit | CanCanCan | rolify |
|---|---|---|---|---|
| Persisted role/permission model | ✅ | ❌ | Partial | Roles only |
| Admin UI to manage roles/permissions | ✅ | ❌ | ❌ | ❌ |
| Audit log of changes | ✅ | ❌ | ❌ | ❌ |
| Record-level authorization (per-instance rules) | Via Pundit | ✅ | ✅ | ❌ |
That split is deliberate: Argus::Trail owns what roles/permissions exist and who has them; Pundit (if you use it) still owns per-record authorization logic like "can this user edit this specific invoice" — the two compose rather than compete.