activerecord-hackery/squeel
Active Record, improved. Live again :)
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.
- ✓14 active contributors
- ✓Distributed ownership (top contributor 42% 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/activerecord-hackery/squeel)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/activerecord-hackery/squeel on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: activerecord-hackery/squeel
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/activerecord-hackery/squeel 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
- 14 active contributors
- Distributed ownership (top contributor 42% 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 activerecord-hackery/squeel
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/activerecord-hackery/squeel.
What it runs against: a local clone of activerecord-hackery/squeel — 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 activerecord-hackery/squeel | 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 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 1532 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of activerecord-hackery/squeel. If you don't
# have one yet, run these first:
#
# git clone https://github.com/activerecord-hackery/squeel.git
# cd squeel
#
# 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 activerecord-hackery/squeel and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "activerecord-hackery/squeel(\\.git)?\\b" \\
&& ok "origin remote is activerecord-hackery/squeel" \\
|| miss "origin remote is not activerecord-hackery/squeel (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"
# 4. Critical files exist
test -f "lib/squeel.rb" \\
&& ok "lib/squeel.rb" \\
|| miss "missing critical file: lib/squeel.rb"
test -f "lib/squeel/dsl.rb" \\
&& ok "lib/squeel/dsl.rb" \\
|| miss "missing critical file: lib/squeel/dsl.rb"
test -f "lib/squeel/nodes.rb" \\
&& ok "lib/squeel/nodes.rb" \\
|| miss "missing critical file: lib/squeel/nodes.rb"
test -f "lib/squeel/adapters/active_record/relation_extensions.rb" \\
&& ok "lib/squeel/adapters/active_record/relation_extensions.rb" \\
|| miss "missing critical file: lib/squeel/adapters/active_record/relation_extensions.rb"
test -f "lib/squeel/visitors/visitor.rb" \\
&& ok "lib/squeel/visitors/visitor.rb" \\
|| miss "missing critical file: lib/squeel/visitors/visitor.rb"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1532 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1502d)"
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/activerecord-hackery/squeel"
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
Squeel is a Ruby DSL layer on top of Active Record that replaces SQL string fragments with expressive Ruby block syntax, leveraging Arel under the hood. It lets developers write Article.where{created_at >= 2.weeks.ago} instead of Article.where(['created_at >= ?', 2.weeks.ago]), making query composition type-safe and more readable. Monolithic lib/ structure with version-specific adapter subdirectories: lib/squeel/adapters/active_record/{3.0,3.1,3.2,4.0,4.1,4.2}/ each containing compat, context, join_dependency_extensions, relation_extensions, and preloader_extensions. Core DSL logic in lib/squeel.rb with a Rails generator in lib/generators/squeel/initializer_generator.rb.
👥Who it's for
Ruby on Rails developers building data-heavy applications who want to avoid SQL string interpolation in queries and prefer composable, Ruby-native query syntax. Specifically targets those using Rails 3.0 through 4.2 who value readability and refactoring safety.
🌱Maturity & risk
Archived and no longer actively maintained (as stated in README). The project reached ~300KB of Ruby code with multi-version Active Record adapter support (3.0 through 4.2), full RSpec test coverage (.rspec present), and Travis CI integration. Status: archived / deprecated — not recommended for new production projects.
High risk: Project is officially archived with no recent commits visible. Tight coupling to specific Active Record versions (3.0–4.2) means it will not work with Rails 5+. Single-maintainer project (Ernie) with no visible governance transfer. No evidence of security patches or bug fixes in recent history.
Active areas of work
Nothing. Project is archived. No active development, PRs, or issues are being addressed.
🚀Get running
Clone the repo and bundle (it's Ruby-only, no build step). git clone https://github.com/activerecord-hackery/squeel.git && cd squeel && bundle install. Note: Only works with Rails 3.0–4.2; modern Rails projects cannot use this.
Daily commands:
bundle exec rspec to run the test suite (RSpec configured in .rspec). No server to start—this is a query DSL library, not an application.
🗺️Map of the codebase
lib/squeel.rb— Main entry point that loads the DSL and adapters; every contributor must understand what Squeel exportslib/squeel/dsl.rb— Core DSL implementation using blocks to enable Ruby-based query syntax; foundational to Squeel's value propositionlib/squeel/nodes.rb— Node abstraction layer that represents all query elements (predicates, functions, joins); the semantic backbonelib/squeel/adapters/active_record/relation_extensions.rb— Integrates Squeel's DSL into ActiveRecord::Relation; the bridge between user code and AR internalslib/squeel/visitors/visitor.rb— Base visitor pattern implementation that converts Squeel nodes to Arel AST; critical for query compilationlib/squeel/context.rb— Execution context for DSL blocks that resolves method_missing to attributes/associations; enables the DSL magiclib/squeel/adapters/active_record.rb— ActiveRecord adapter loader that selects version-specific implementations (3.0–4.2); version compatibility hub
🛠️How to make changes
Add a new node type (e.g., WINDOW function)
- Create node class in lib/squeel/nodes/, inheriting from Node or appropriate parent (e.g., Unary, Binary) (
lib/squeel/nodes/window.rb (new)) - Export the new class in lib/squeel/nodes.rb (
lib/squeel/nodes.rb) - Add a visitor method (e.g., visit_window) in lib/squeel/visitors/visitor.rb (
lib/squeel/visitors/visitor.rb) - Add context method in lib/squeel/context.rb if exposing to DSL blocks (
lib/squeel/context.rb) - Write tests exercising the node and visitor (
spec/squeel/nodes/window_spec.rb (new))
Support a new Rails version (e.g., Rails 5.0)
- Create version directory with compat.rb, context.rb, relation_extensions.rb, etc. (
lib/squeel/adapters/active_record/5.0/ (new directory)) - Copy and adapt from previous version (e.g., 4.2), updating method signatures as needed (
lib/squeel/adapters/active_record/4.2/*.rb (reference)) - Update lib/squeel/adapters/active_record.rb to require the new version module (
lib/squeel/adapters/active_record.rb) - Test with Rails 5.0 in spec matrix (
.travis.yml)
Add a new predicate operator (e.g., ILIKE)
- Define method in lib/squeel/nodes/predicate_methods.rb (
lib/squeel/nodes/predicate_methods.rb) - Ensure lib/squeel/nodes/predicate.rb handles it in operator mapping (
lib/squeel/nodes/predicate.rb) - Add visitor logic in lib/squeel/visitors/predicate_visitor.rb to map to Arel (
lib/squeel/visitors/predicate_visitor.rb)
Enable Symbol core extensions in a fresh app
- Run rails generator to create config file (
Command: rails g squeel:initializer) - Uncomment enable_core_extensions in generated file (
config/initializers/squeel.rb) - Use Symbol#asc, #desc, #func syntax in queries without manually creating node objects (
lib/squeel/core_ext/symbol.rb (consumed))
🔧Why these technologies
- Arel (Abstract Relational Algebra) — Squeel compiles to Arel to leverage ActiveRecord's existing SQL generation, ensuring DB compatibility
- Ruby blocks & method_missing — Enables Ruby-syntax queries; method_missing on Context captures attribute access without pre-registration
- Visitor pattern — Clean separation: nodes represent query semantics, visitors handle SQL dialects and Rails version differences
- Version-specific adapters — Monkeypatching AR internals (JoinDependency, Preloader) requires per-Rails-version shims
⚖️Trade-offs already made
-
Monkeypatch ActiveRecord internals rather than fork AR
- Why: Minimal footprint, leverage AR updates automatically
- Consequence: Brittle across Rails versions; high maintenance burden; breaks on AR internals changes
-
Eager evaluation of block via method_missing vs lazy AST building
- Why: Simpler user API (looks like Ruby code, immediate feedback)
- Consequence: Harder to introspect queries before execution; debug stack traces can be confusing
-
Optional core_ext (Symbol#asc, Hash shorthand) rather than mandatory
- Why: Non-invasive; users opt-in to monkey-patching stdlib
- Consequence: More verbose syntax if extensions disabled; two code styles in ecosystem
-
Archived (no longer maintained)
- Why: Rails moved away from query DSLs (Arel exposure reduced); maintenance burden unsustainable
- Consequence: Incompatible with Rails 5.0+; no bug fixes; community must fork
🚫Non-goals (don't propose these)
- Support Rails 5.0 and newer (archived before Rails 5.0 stabilized)
- Real-time query optimization or caching
- Non-SQL databases (MongoDB, Cassandra); Squeel is ActiveRecord-specific
- Backwards compatibility with hand-written
🪤Traps & gotchas
Critical gotcha explicitly warned in README: Inside Squeel DSL blocks (using {}), self is reassigned via instance_eval, so instance variables like @user and instance methods won't work directly without workarounds (use local assignment, arity parameter with |q| prefix, or my{} wrapper). Version-specific behavior: each Rails version (3.0–4.2) has its own adapter folder with subtly different implementations due to Active Record API churn; using the wrong adapter for your Rails version will silently fail or crash.
🏗️Architecture
💡Concepts to learn
- instance_eval-based DSL — Squeel's entire DSL is built on
instance_evalto rebindselfinside blocks; understanding its scope-rebinding behavior and gotchas is essential to using Squeel correctly and avoiding bugs with instance variables - Arel (Active Record Expression Language) — Squeel is a thin DSL wrapper around Arel; Squeel translates Ruby blocks into Arel AST nodes, so understanding Arel's predicate and expression objects is key to extending Squeel
- Active Record Relation/JoinDependency monkey-patching — Squeel modifies Active Record's internals (Relation, JoinDependency, Preloader) via adapters; this version-specific patching is fragile and explains why Squeel broke on Rails 5+ API changes
- Predicate objects (Arel::Nodes::Equality, etc.) — Squeel DSL blocks return Arel predicate objects (e.g.,
created_at >= 2.weeks.agobecomes anArel::Nodes::GreaterThanOrEqual); understanding predicate composition is essential for writing complex Squeel queries - Stubs and keypaths (symbol-based query navigation) — Squeel's core DSL concept; stubs represent table columns and keypaths represent associations; the README hints at these but implementation details are in context.rb files, crucial for understanding query composition
- Rails version adapter pattern — Squeel uses subdirectories (3.0, 3.1, 3.2, 4.0, 4.1, 4.2) to isolate version-specific code; this pattern shows how to maintain a library across major framework versions—and why it's unsustainable without active maintenance
- Block arity and parameter binding — Squeel DSL blocks can take parameters (e.g.,
where{|q| q.name == 'foo'}) to access the DSL object explicitly; understanding arity-based parameter handling is needed to avoid the instance variable gotcha
🔗Related repos
rails/rails— Squeel depends entirely on Active Record and Arel; understanding AR internals is essential to understanding Squeel's adapter patternbrynary/arel-helpers— Similar goal (making Arel more accessible) but lighter-weight and less invasive than Squeel; a modern alternative approachactiverecord-hackery/ransack— Same org, similar philosophy of improving AR query DSL; Ransack is actively maintained and focused on search/filteringactiverecord-hackery/polyamorous— Companion library by same org; handles complex joins and polymorphic associations for AR querieseladmeidar/activerecord_where_assoc— Modern maintained alternative solving a subset of Squeel's problem (cross-association querying) for Rails 5+
🪄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 test suite for Rails 5.0+ adapter compatibility
The repo has version-specific adapters up to Rails 4.2 (lib/squeel/adapters/active_record/4.2/) but no 5.0, 5.1, 5.2, 6.0+ adapters despite the README claiming the project is 'Live again'. This is a critical gap for modern Rails applications. Adding adapter versions and corresponding specs would make the gem usable for current Rails versions.
- [ ] Create lib/squeel/adapters/active_record/5.0/ directory with compat.rb, context.rb, relation_extensions.rb, preloader_extensions.rb following the 4.2 pattern
- [ ] Create lib/squeel/adapters/active_record/5.1/ and 5.2/ with minimal deltas from 5.0
- [ ] Add spec/adapters/rails_5_0_spec.rb and spec/adapters/rails_5_1_spec.rb with version-specific integration tests
- [ ] Update lib/squeel/adapters/active_record.rb to auto-detect and load appropriate version adapter
- [ ] Update .travis.yml to test against Rails 5.0, 5.1, 5.2, 6.0 versions
Add integration tests for DSL core features in lib/squeel/nodes/
The nodes directory contains key abstractions (KeyPath, Function, Join, Aliasing, And, Binary) but there's no spec/nodes/ directory visible in the structure. These are the core building blocks of Squeel's DSL and need tests verifying their behavior with actual Active Record queries.
- [ ] Create spec/nodes/ directory structure mirroring lib/squeel/nodes/
- [ ] Add spec/nodes/key_path_spec.rb testing nested attribute access (e.g., article{comments.author.name})
- [ ] Add spec/nodes/function_spec.rb testing SQL function wrapping (e.g., {MAX(id)}, {COALESCE(...)})
- [ ] Add spec/nodes/join_spec.rb testing join type specification and alias handling
- [ ] Verify each spec generates correct SQL via generated_sql matcher
Document and test the DSL block syntax edge cases in README.md and add comprehensive examples spec
The README is truncated ('If you'd like to customize Squeel's fu') and lacks examples of complex DSL usage patterns. The lib/squeel/dsl.rb file likely contains the core DSL implementation but typical usage patterns aren't documented. Adding a spec/dsl_examples_spec.rb with real-world query patterns would serve as both tests and documentation.
- [ ] Create spec/dsl_examples_spec.rb with realistic query examples: joins with conditions, nested blocks, function calls, OR/AND combinations
- [ ] Add RSpec shared examples for common DSL patterns (e.g., 'shared_examples_for "polymorphic joins"')
- [ ] Complete README.md documentation section with at least 5 working code examples showing DSL vs SQL equivalents
- [ ] Add doc/DSL_GUIDE.md with detailed examples of KeyPath traversal, Function usage, and Join customization
- [ ] Ensure all examples in specs have corresponding SQL output comments for verification
🌿Good first issues
- Add integration specs for Squeel DSL block arity parameter (
|q|syntax) across all supported Rails versions; currently unclear which versions are fully tested for this edge case. - Document the exact
my{}wrapper behavior for accessing external instance variables; the README mentions it exists but provides minimal examples—create a spec file showing all three workaround patterns in action. - Add backwards-compatibility guide: create a spec file showing what breaks when upgrading from Squeel + Rails 4.2 to Rails 5+, and what the equivalent Arel code looks like (helps users migrate off this library).
⭐Top contributors
Click to expand
Top contributors
- @ernie — 42 commits
- @bigxiang — 35 commits
- @danielrhodes — 5 commits
- @joseluistorres — 4 commits
- @radar — 2 commits
📝Recent commits
Click to expand
Recent commits
46072cf— Archive notice (scarroll32)5542266— Bump to 1.2.3 (bigxiang)32f13d1— Merge pull request #360 from activerecord-hackery/new_rails_dependency_and_ci_env (bigxiang)ddf209a— [ci skip] Edit change log. (bigxiang)6562716— Support 4.1.9+ and the latest 4-2-stable. (bigxiang)f0dbce7— Revert the change for 4.1. (bigxiang)3c96604— Change Ruby versions for CI. (bigxiang)6ab44c6— Fix Rails 4.2 spec error. (bigxiang)05c9071— Lock Rails version to 4.2 instead of master. (bigxiang)e7f0168— Backwards compatibility fix for Active Record 4.1 (danielrhodes)
🔒Security observations
- High · SQL Injection Risk via DSL Query Building —
lib/squeel/visitors/, lib/squeel/adapters/active_record/, lib/squeel/nodes/. Squeel is a Ruby DSL that builds Arel queries for Active Record. The library processes user input through a domain-specific language to construct SQL queries. While Squeel uses Arel underneath (which has parameterization), the DSL evaluation and transformation could introduce injection vectors if user input is not properly sanitized before being passed to the DSL blocks. The file structure suggests complex query transformation logic across multiple visitor and adapter files that could be exploited. Fix: Ensure all user-supplied input passed to Squeel DSL blocks is validated and sanitized. Review visitor implementations (enumeration_visitor.rb, from_visitor.rb, etc.) to confirm parameterized queries are used throughout. Add input validation at DSL entry points. Consider restricting DSL to trusted code only. - High · Archived Project with No Active Maintenance —
README.md, project root. The README explicitly states 'This project is archived.' This means the codebase is no longer actively maintained and will not receive security updates, bug fixes, or vulnerability patches. Any dependencies it relies on may become vulnerable over time as those packages are updated. Fix: Do not use this library in production. Consider migrating to actively maintained alternatives or forking and maintaining internally if necessary. If already in use, audit all dependencies for known vulnerabilities and plan a migration strategy. - High · Dynamic Code Evaluation Risk —
lib/squeel/dsl.rb, lib/squeel/nodes/, lib/squeel/context.rb. The library uses block-based DSL (evident from README examples likeArticle.where{created_at >= 2.weeks.ago}). This requires dynamic evaluation of user-provided blocks in a context that modifies method resolution. If blocks contain arbitrary Ruby code, this could lead to unintended code execution or method hijacking attacks. Fix: Document the DSL's security model clearly. Ensure blocks are evaluated in a restricted context with method whitelisting. Avoid eval() or instance_eval() on untrusted input. Implement proper scoping and context isolation for DSL evaluation. - Medium · No Dependency File Available for Analysis —
Gemfile, gemspec files. The dependencies/package file content is missing from the analysis. This prevents verification of known vulnerabilities in direct and transitive dependencies. The project uses Arel and Active Record, which themselves need to be audited for security issues. Fix: Analyze the Gemfile and .gemspec to identify all dependencies. Run 'bundle audit' or 'bundler-audit' to check for known vulnerabilities in gems. Maintain dependency versions and perform regular security audits. - Medium · Multiple Rails Version Adapters Increase Attack Surface —
lib/squeel/adapters/active_record/3.0/, 3.1/, 3.2/. The codebase includes adapters for Rails 3.0 through 4.2, with version-specific code paths. This multi-version support increases code complexity and the potential for version-specific vulnerabilities. Older Rails versions (3.0, 3.1, 3.2) have known security issues and should not be used in production. Fix: Remove adapters for deprecated Rails versions. Only support Rails versions that receive security updates. Test thoroughly when supporting multiple versions to ensure no version-specific vulnerabilities are introduced. - Medium · Core Extensions Modify Built-in Classes —
lib/squeel/core_ext/symbol.rb, lib/squeel/core_ext/hash.rb. The library modifies core Ruby classes (Symbol, Hash) via core_ext. This can cause namespace pollution, conflicts with other libraries, or unexpected behavior if modifications are not carefully implemented. Fix: Review core extensions to ensure they don't conflict with other libraries. Consider using refinements (Ruby 2.0+) instead of global modifications. Thoroughly test interactions with other gems that modify the same classes. - Low · Generator Template Lacks Security Review —
lib/generators/templates/squeel.rb. The project includes a generator that creates initialization code. If the template contains insecure defaults or doesn't provide adequate security guidance, users may deploy with insecure configurations. Fix: Review the initializer template to ensure it does not set insecure defaults. Add security-related comments and documentation. Consider requiring explicit opt-
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.