ryanb/cancan
Authorization Gem for Ruby on Rails.
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓40+ active contributors
- ✓Distributed ownership (top contributor 46% of recent commits)
- ✓MIT licensed
Show 3 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Stale — last commit 4y ago
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/ryanb/cancan)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/ryanb/cancan on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: ryanb/cancan
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/ryanb/cancan shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- 40+ active contributors
- Distributed ownership (top contributor 46% of recent commits)
- MIT licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 4y ago
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live ryanb/cancan
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/ryanb/cancan.
What it runs against: a local clone of ryanb/cancan — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in ryanb/cancan | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | Last commit ≤ 1640 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of ryanb/cancan. If you don't
# have one yet, run these first:
#
# git clone https://github.com/ryanb/cancan.git
# cd cancan
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of ryanb/cancan and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "ryanb/cancan(\\.git)?\\b" \\
&& ok "origin remote is ryanb/cancan" \\
|| miss "origin remote is not ryanb/cancan (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1640 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1610d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/ryanb/cancan"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
CanCan is a Ruby on Rails authorization gem that centralizes all user permission logic in a single Ability class, allowing developers to define what resources each user can access and then automatically enforce those rules across controllers, views, and database queries without duplication. It supports multiple ORMs (ActiveRecord, DataMapper, Mongoid) and provides DSL methods like can?, cannot?, and authorize! to check and enforce permissions throughout the application. Monolithic gem structure: core logic in lib/cancan/ with four layers—ability.rb (DSL and rule storage), rule.rb (individual permission rules), controller_additions.rb (Rails integration), and lib/cancan/model_adapters/ (ORM abstraction for ActiveRecord, DataMapper, Mongoid, etc.). Generator in lib/generators/cancan/ability/ scaffolds the initial Ability class. Tests parallel the lib/ structure under spec/.
👥Who it's for
Rails developers building applications that need fine-grained access control—specifically those who want to move authorization logic out of scattered controller conditionals and into a maintainable, testable central location. Also for developers integrating with authentication systems like Devise or Authlogic who need a corresponding authorization layer.
🌱Maturity & risk
CanCan is unmaintained and officially abandoned (see README: 'The CanCan gem is no longer maintained'). The codebase is mature (built around Rails 3–4 era with 144K LOC of Ruby) and includes a full test suite (spec/ directory with RSpec), but the project stopped receiving updates years ago. The recommendation is to migrate to CanCanCan (community fork) or Pundit instead.
High risk for new projects: this gem receives no maintenance, meaning compatibility with modern Rails versions (7+) is not guaranteed and security vulnerabilities will not be patched. Single-maintainer legacy project (ryanb) with no active development. Existing apps using it will accumulate technical debt as dependencies (Rails, Ruby) evolve. Breaking changes in Rails or ActiveRecord are unlikely to be addressed.
Active areas of work
Nothing. This is a dormant project. The last commit was years ago, no open PRs are being merged, and the README explicitly directs users to alternatives (CanCanCan, Pundit). The .travis.yml and test suite remain but are not actively run.
🚀Get running
git clone https://github.com/ryanb/cancan.git
cd cancan
bundle install
bundle exec rspec
Note: This project is not recommended for new work; consider CanCanCan or Pundit instead.
Daily commands:
bundle exec rspec # Run full test suite
bundle exec rspec spec/cancan/ability_spec.rb # Run specific test file
This is a library, not a runnable application. To use it in a Rails app: generate Ability class with rails g cancan:ability, then define rules in app/models/ability.rb.
🗺️Map of the codebase
- lib/cancan/ability.rb: Core DSL and permission engine; defines
canandcannotrules, parses conditions, and evaluates user abilities—every authorization decision flows through here. - lib/cancan/controller_additions.rb: Rails controller integration; provides
load_and_authorize_resource,authorize!,can?,cannot?helpers injected into all controllers. - lib/cancan/rule.rb: Represents a single permission rule (action + resource + conditions); rules are stored in Ability and matched during authorization checks.
- lib/cancan/model_adapters/: Multi-ORM abstraction layer; abstract_adapter.rb defines interface, then active_record_adapter.rb, mongoid_adapter.rb, etc. implement ORM-specific query translation for scoping authorized records.
- lib/cancan/controller_resource.rb: Bridges controller actions to resource loading and authorization; handles the before_filter behavior of
load_and_authorize_resource. - lib/generators/cancan/ability/ability_generator.rb: Rails generator scaffolding; creates initial app/models/ability.rb stub with the class skeleton and initialize method.
- spec/cancan/ability_spec.rb: Comprehensive test suite for the Ability class; shows expected DSL behavior, condition matching, and rule precedence—primary reference for how rules work.
🛠️How to make changes
Define permissions: Edit or create app/models/ability.rb (initialized by generator at lib/generators/cancan/ability/templates/ability.rb). Add authorization to controllers: Use load_and_authorize_resource in lib/cancan/controller_additions.rb-integrated controllers. Add new ORM adapter: Create new file in lib/cancan/model_adapters/ following the pattern of active_record_adapter.rb. Extend DSL: Modify lib/cancan/ability.rb to add new rule types. Tests: Add specs in spec/cancan/ mirroring the lib structure.
🪤Traps & gotchas
current_usermust exist: CanCan assumes acurrent_userhelper in controllers; authentication must be set up separately (Devise, Authlogic, etc.) and will fail silently if missing. 2. Eager loading & N+1 queries: The DSL hides complex database queries; querying a collection with many permissions can generate slow SQL. Must explicitly inspect generated queries. 3. Symbol vs. Class matching: Rules defined with symbols (:read) vs. class references (Article) match differently; mixing them causes subtle permission leaks. 4. Inheritance of abilities: Ability rules are evaluated in order; later rules override earlier ones, but nested conditionals can be confusing. 5. ORM mismatch: Model adapters are ORM-specific; mixing ActiveRecord and Mongoid queries in one app or using unsupported ORMs will fail.
💡Concepts to learn
- Adapter Pattern (ORM Abstraction) — CanCan uses adapters (lib/cancan/model_adapters/) to translate permission rules into ORM-specific queries; understanding this pattern is essential for extending CanCan to unsupported databases or optimizing query generation.
- Rule Evaluation & Precedence — CanCan evaluates rules in definition order and stops at first match; later rules override earlier ones. Misunderstanding precedence leads to unintended permission grants or denials.
- Condition Matching (Hashes & Procs) — Rules can include conditions as hashes (translated to SQL WHERE clauses) or procs (evaluated in Ruby); mixing them incorrectly causes rules that work in controllers but fail in database queries.
- Before Filters (ActionController Callbacks) — CanCan's
load_and_authorize_resourceis a Rails before_filter that intercepts controller actions; understanding Rails filter chain order is critical for debugging permission checks that fail at unexpected times. - Scoped Authorization (Active Record Scopes) — CanCan can scope resource collections (e.g., @articles = Article.accessible_by(current_ability)) using generated scopes; this is the key to avoiding N+1 queries and bulk operations on authorized records.
- DSL (Domain-Specific Language) — CanCan's
canandcannotmethods create a readable, Ruby-like syntax for permissions; understanding how the DSL is parsed (lib/cancan/ability.rb) helps when writing complex ability rules. - Declarative Authorization — CanCan uses declarative style (define what users can do) vs. imperative (scattered if-checks in controllers); this centralization is its core value but requires shifting mental model from controller-local logic.
🔗Related repos
CanCanCommunity/cancancan— Community fork and active successor to ryanb/cancan; maintains API compatibility while adding Rails 5+ support and bug fixes—the recommended migration target.varvet/pundit— Lightweight authorization gem with different philosophy (policy objects per model vs. centralized Ability); main competitor and alternative recommendation in CanCan's README.collectiveidea/authorization— Older Rails authorization gem; predecessor pattern that influenced CanCan's design but less feature-complete.binarylogic/authlogic— Authentication gem frequently paired with CanCan; providescurrent_userthat CanCan depends on and is mentioned in README setup.plataformatec/devise— More modern authentication gem than Authlogic; also pairs with CanCan to provide complete auth + authz stack, mentioned in README as alternative authentication source.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive tests for lib/cancan/model_adapters/mongoid_adapter.rb with edge cases
The Mongoid adapter exists but likely lacks coverage for complex query scenarios, nested permissions, and edge cases that differ from ActiveRecord. Given that CanCan supports multiple ORMs (ActiveRecord, DataMapper, Mongoid), the Mongoid adapter should have parity in test coverage. spec/cancan/model_adapters/mongoid_adapter_spec.rb exists but is likely sparse, especially for Mongoid-specific features like field projections, aggregation pipelines, and document inheritance.
- [ ] Review spec/cancan/model_adapters/mongoid_adapter_spec.rb for coverage gaps
- [ ] Add tests for Mongoid-specific query patterns (e.g., where with multiple conditions, nested document queries)
- [ ] Add tests for permission scoping with Mongoid's DSL (where, all, exists, etc.)
- [ ] Add integration tests for lib/cancan/model_adapters/mongoid_adapter.rb with real Mongoid document classes
- [ ] Verify all tests pass against current Mongoid versions
Add missing tests for lib/cancan/inherited_resource.rb integration scenarios
The inherited_resources gem integration (lib/cancan/inherited_resource.rb) exists but spec/cancan/inherited_resource_spec.rb likely lacks coverage for real-world controller scenarios with custom actions, nested resources, and permission denials. This is critical since inherited_resources is a popular Rails pattern that users combine with CanCan.
- [ ] Review spec/cancan/inherited_resource_spec.rb for gaps in nested resource testing
- [ ] Add tests for permission checks on custom inherited_resources actions (new, create, edit, update, destroy)
- [ ] Add tests for nested resource authorization (e.g., /authors/:author_id/books/:id)
- [ ] Add tests for authorization failures raising CanCan::AccessDenied exceptions
- [ ] Add tests for load_and_authorize_resource with inherited_resources override scenarios
Refactor lib/cancan/controller_additions.rb into separate concern modules for readability
controller_additions.rb likely contains multiple concerns (authorize_resource, load_resource, check_authorization, rescue_cancan_exception) mixed in a single file. This large file should be split into separate, focused modules for maintainability. The spec/cancan/controller_additions_spec.rb shows broad coverage but the source file organization makes future contributions harder.
- [ ] Analyze lib/cancan/controller_additions.rb to identify distinct concern modules
- [ ] Create lib/cancan/controller_additions/authorization_helper.rb for authorize_resource logic
- [ ] Create lib/cancan/controller_additions/resource_loader.rb for load_resource logic
- [ ] Create lib/cancan/controller_additions/exception_handler.rb for rescue logic
- [ ] Update lib/cancan/controller_additions.rb to include and compose these modules
- [ ] Ensure all existing tests in spec/cancan/controller_additions_spec.rb still pass without modification
🌿Good first issues
- Add integration tests for Rails 6+ and Rails 7: The test suite predates modern Rails; adding spec files under spec/cancan/ that verify CanCan works with current Rails versions (using new Zeitwerk autoloading, encrypted credentials, etc.) would help users assess adoption risk.
- Document migration path from CanCan to CanCanCan: Create a MIGRATION.md guide in the root showing exact code diffs for common Ability patterns (can :manage, :all; scoped queries; attribute-based rules) translated to CanCanCan syntax, since users are stranded.
- Add type hints or YARD documentation to model_adapters/: The adapter interface in abstract_adapter.rb is poorly documented; adding YARD comments and concrete examples for ActiveRecordAdapter.queryable_options and authorize_resource would help anyone extending for custom ORMs.
⭐Top contributors
Click to expand
Top contributors
- @ryanb — 46 commits
- @nashby — 9 commits
- @andhapp — 4 commits
- [@Roland Venesz](https://github.com/Roland Venesz) — 2 commits
- @DavidMikeSimon — 2 commits
📝Recent commits
Click to expand
Recent commits
705b5d6— Add unmaintained notice (ryanb)4560928— Merge pull request #848 from twe4ked/fix-generated-file-whitespace (nashby)f6c1052— Merge pull request #841 from nicolasiensen/patch-1 (nashby)d7bd6b1— Merge pull request #828 from vfrride/patch-1 (nashby)2d50734— Merge pull request #926 from benmoss/patch-1 (nashby)acf12c3— Merge pull request #903 from kimberninger/patch-1 (nashby)750e377— Fix docs typo (benmoss)c1979e8— Fixed a typo in README.rdoc (kimberninger)440bd88— Merge pull request #898 from inossidabile/typo-fix (jeremyf)1f3ca49— Comment typo fixed (inossidabile)
🔒Security observations
CanCan presents significant security concerns primarily because it is no longer actively maintained. While the codebase shows reasonable authorization architecture, the lack of maintenance means security vulnerabilities will not be patched. Additionally, potential injection vulnerabilities in model adapters require careful review. The authorization mechanism itself requires secure integration patterns that may not be immediately obvious to users. Migration to a maintained alternative (CanCanCan or Pundit) is strongly recommended.
- Critical · Unmaintained Project —
README.rdoc, Project Status. The CanCan gem is no longer actively maintained according to the README. This means security vulnerabilities discovered in the future will not be patched. The project explicitly recommends using CanCanCan or Pundit instead. Fix: Migrate to an actively maintained authorization library such as CanCanCan (https://github.com/CanCanCommunity/cancancan) or Pundit (https://github.com/varvet/pundit). Do not use CanCan in new projects or applications requiring security updates. - High · Potential SQL Injection in Model Adapters —
lib/cancan/model_adapters/active_record_adapter.rb, lib/cancan/model_adapters/data_mapper_adapter.rb, lib/cancan/model_adapters/mongoid_adapter.rb. The codebase includes multiple model adapters (ActiveRecord, DataMapper, Mongoid) that construct queries based on ability rules. Without seeing the actual implementation, there is a significant risk that dynamic query construction could be vulnerable to SQL injection if user input is not properly parameterized. Fix: Review all query construction code to ensure parameterized queries are used exclusively. Audit the Rule class to ensure conditions cannot be manipulated by user input. Consider using ORM-provided query methods rather than raw SQL strings. - High · Missing Security Headers and CSRF Protection Integration —
lib/cancan/controller_additions.rb. The controller_additions module integrates with Rails controllers but there is no visible documentation or implementation of Rails security headers (CSP, X-Frame-Options, etc.) or CSRF token validation for authorization checks. Fix: Ensure all controller actions are protected with Rails CSRF tokens. Implement Content Security Policy (CSP) headers to mitigate XSS risks. Use Rails security headers middleware to set appropriate security headers. - Medium · Potential Authorization Bypass in Resource Loading —
lib/cancan/controller_resource.rb. The ControllerResource class automatically loads resources from parameters without explicit authorization checks visible in the file structure. This could lead to authorization bypasses if not properly implemented. Fix: Verify that all resource loading operations in ControllerResource explicitly check authorization before returning the resource. Implement allow-list based authorization rather than deny-list. Add comprehensive tests for authorization bypass scenarios. - Medium · No Visible Input Validation Framework —
lib/cancan/. While CanCan is primarily an authorization library, there is no visible input validation framework or helpers to prevent injection attacks. Authorization alone cannot prevent XSS or injection vulnerabilities. Fix: Implement or recommend input validation and output encoding best practices. Use Rails built-in sanitization helpers (sanitize, h, etc.). Validate all user inputs server-side regardless of client-side validation. - Low · Outdated Dependencies —
Gemfile, cancan.gemspec. No Gemfile content was provided for analysis, but given this project is unmaintained, all dependencies are likely outdated and may contain known vulnerabilities. Fix: Run 'bundle audit' to identify known vulnerabilities in dependencies. Update all gems to the latest versions or migrate to a maintained authorization library with up-to-date dependencies. - Low · Missing Security Documentation —
README.rdoc. The README does not include security best practices, common pitfalls, or security considerations for users of the library. Fix: Add a security section to documentation covering: proper ability definition patterns, common authorization mistakes, and integration with Rails security features.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.