stefankroes/ancestry
Organise ActiveRecord model into a tree structure
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.
- ✓Last commit 6d ago
- ✓2 active contributors
- ✓MIT licensed
Show 4 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Small team — 2 contributors active in recent commits
- ⚠Single-maintainer risk — top contributor 99% of recent commits
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/stefankroes/ancestry)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/stefankroes/ancestry on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: stefankroes/ancestry
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/stefankroes/ancestry 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
- Last commit 6d ago
- 2 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Small team — 2 contributors active in recent commits
- ⚠ Single-maintainer risk — top contributor 99% of recent commits
<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 stefankroes/ancestry
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/stefankroes/ancestry.
What it runs against: a local clone of stefankroes/ancestry — 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 stefankroes/ancestry | 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 ≤ 36 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of stefankroes/ancestry. If you don't
# have one yet, run these first:
#
# git clone https://github.com/stefankroes/ancestry.git
# cd ancestry
#
# 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 stefankroes/ancestry and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "stefankroes/ancestry(\\.git)?\\b" \\
&& ok "origin remote is stefankroes/ancestry" \\
|| miss "origin remote is not stefankroes/ancestry (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 36 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~6d)"
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/stefankroes/ancestry"
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
Ancestry is a Ruby gem that organizes ActiveRecord models into tree/hierarchical structures using the materialized path pattern—storing ancestor chains in a single indexed column (e.g., 1/2/3/) rather than requiring extra tables. It provides single-query access to ancestors, descendants, siblings, children, and leaves with real ActiveRecord associations and depth caching. Modular structure: lib/ancestry.rb is the entry point, delegating to lib/ancestry/has_ancestry.rb (the DSL), lib/ancestry/class_methods.rb (scope/finder methods), lib/ancestry/instance_methods.rb (node operations), and lib/ancestry/adapter.rb (database abstraction). Includes database-specific adapters (ltree.rb for PostgreSQL). Extensive test suite and Mermaid diagrams in img/ document tree navigation patterns.
👥Who it's for
Rails developers building hierarchical data models (org charts, category trees, comment threads, file systems) who need efficient tree queries without the complexity of adjacency lists or nested set models. Used by maintainers of large Rails applications requiring production-grade tree navigation.
🌱Maturity & risk
Production-ready and actively maintained. The gem has CI/CD via GitHub Actions (.github/workflows/run_test_suite.yml), supports Rails 6.0–8.1 via Appraisals (gemfiles/ directory with 8 versions), includes detailed CONFIGURATION.md documentation, and the codebase shows consistent updates. This is a stable, battle-tested solution used in production systems.
Low risk overall. Single maintainer (stefankroes) is a potential concern, but the gem has minimal dependencies (pure Ruby + Rails), strong test coverage evident from CI setup, and the materialized path pattern is database-agnostic. Main risk: upgrading between major Rails versions requires running test matrix, and custom database adapters (see lib/ancestry/ltree.rb for PostgreSQL ltree support) add complexity for edge cases.
Active areas of work
Actively maintained with support for modern Rails versions (8.0, 8.1 in Appraisals). Recent work includes real ActiveRecord associations (belongs_to :parent, has_many :children), cached columns, counter caches, and depth constraints. GitHub workflows validate against multiple Ruby/Rails combinations. The project follows semantic versioning with a detailed CHANGELOG.md.
🚀Get running
git clone https://github.com/stefankroes/ancestry.git
cd ancestry
bundle install
bundle exec rake test
Daily commands:
This is a library, not an application. To test locally: bundle exec rake test (uses appraisal to test against all supported Rails versions). Run a specific version: appraisal gemfile_81 bundle exec rake test. Interactive console: bin/console (loads the gem and a dummy Rails app).
🗺️Map of the codebase
- lib/ancestry.rb: Entry point that loads all modules and defines the
has_ancestrymethod injected into ActiveRecord models - lib/ancestry/has_ancestry.rb: Implements the DSL macro (
has_ancestry) that configures tree behavior and options on a model - lib/ancestry/class_methods.rb: Defines all tree traversal scopes (
.ancestors,.descendants,.siblings,.children,.leaves, etc.) as ActiveRecord chains - lib/ancestry/instance_methods.rb: Instance-level tree operations (
parent,root,subtree,path) and helpers likedepthandancestors? - lib/ancestry/adapter.rb: Database abstraction layer handling SQL generation, materialized path manipulation, and format-agnostic queries
- lib/ancestry/ltree.rb: PostgreSQL-specific ltree format adapter providing native tree support; alternative to materialized_path format
- CONFIGURATION.md: Comprehensive guide to all ancestry options, cached columns, integrity checks, and database column setup
- Appraisals: Defines test matrix across Rails 6.0–8.1 versions; critical for validating compatibility before release
🛠️How to make changes
New tree queries: add scope/class method in lib/ancestry/class_methods.rb, update lib/ancestry/instance_methods.rb for instance methods. New options: extend has_ancestry DSL in lib/ancestry/has_ancestry.rb. Database adapter changes: modify lib/ancestry/adapter.rb or add format-specific logic to lib/ancestry/ltree.rb. Tests: place in test/ (following the patterns visible in CI config). Documentation: update CONFIGURATION.md for user-facing features, add Mermaid diagram to img/ for tree navigation visuals.
🪤Traps & gotchas
Materialized path format strings: Ancestry uses / separators by default (e.g., 1/2/3/) but supports alternative formats like materialized_path3 (base-36). Changing format mid-deployment requires custom migration. Collation sensitivity: MySQL requires specific collation (binary/utf8_bin) for ancestry column; the t.ancestry migration helper handles this, but manual column creation can fail silently. STI gotcha: Single Table Inheritance returns all classes from scopes unless explicitly filtered with .where(type: ClassName)—easy to get unintended subclasses. Counter cache updates: If you enable counter_cache: true, parent records are updated on every child change; large trees can see contention. Orphan strategies: Deleting a parent with strategy: :destroy cascades deletions; strategy: :restrict raises errors; strategy: :adopt moves children to grandparent—choose explicitly or risk silent data loss.
💡Concepts to learn
- Materialized Path — Core pattern in Ancestry: each node stores its full ancestor chain as a string (e.g.,
1/5/12/), enabling single-query tree operations via string prefix matching instead of recursive CTEs or closure tables - Adapter Pattern — Ancestry abstracts database-specific SQL generation (
lib/ancestry/adapter.rb) to support MySQL, PostgreSQL, SQLite, and specialized formats like ltree without coupling tree logic to any single DB - Single Table Inheritance (STI) — Ancestry explicitly handles STI where subclasses share the same table; scopes return all classes by default unless filtered—a subtlety noted in the README that can cause unexpected polymorphism
- Denormalization & Counter Caches — Ancestry optionally stores
depthand child counts in separate columns (viacache_depth: true,counter_cache: true) to optimize reads; trades write performance for fast depth queries and parent.children_count - PostgreSQL LTREE — Ancestry's
lib/ancestry/ltree.rbadapter exposes PostgreSQL's native hierarchical ltree type, offering GiST indexes and native operators (@>,<@) for tree queries, an alternative to text-based materialized paths - Orphan Strategies — When a parent node is deleted, Ancestry applies configurable strategies (
:destroycascades,:restrictraises errors,:adoptmoves children to grandparent); critical for data integrity in hierarchical models - ActiveRecord Associations & Eager Loading — Ancestry now generates real
belongs_to :parentandhas_many :childrenassociations, allowing.includes(:children)and.eager_load(:ancestors)for N+1 query prevention in tree traversal
🔗Related repos
ClosureTree/closure_tree— Alternative tree gem using closure table pattern (extra table with all ancestor pairs); better for deep hierarchies but requires more storagecollectiveidea/awesome_nested_set— Nested set pattern implementation; good for pre-order traversal but slower on writes since moving a node updates many recordsrails/rails— Core ActiveRecord dependency; Ancestry extends ActiveRecord with tree capabilities and must maintain compatibility across Rails versionskbrock/tree-bench— Benchmark suite comparing Ancestry, ClosureTree, and AwesomeNestedSet performance; referenced in Ancestry README as performance validationthoughtbot/shoulda-matchers— Testing gem commonly used in Ancestry test suites for Rails integration testing and association matchers
🪄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 materialized_path2 and materialized_path3 adapters
The repo has multiple materialized path implementations (materialized_path.rb, materialized_path2.rb, materialized_path3.rb, materialized_path_array.rb, and ltree.rb) but test/concerns/db_test.rb likely only tests one default adapter. Each adapter may have edge cases, performance characteristics, and compatibility issues that need dedicated test coverage.
- [ ] Review test/concerns/db_test.rb to understand current adapter test patterns
- [ ] Create test/concerns/adapters directory with separate test files for each adapter strategy
- [ ] Add parametrized tests in each file covering: tree construction, querying ancestors/descendants, reordering, and deletion for materialized_path2, materialized_path3, and ltree
- [ ] Ensure test suite runs against all adapters in GitHub Actions (lib/ancestry/materialized_path*.rb implementations)
Add missing tests for edge cases in depth_constraints_test.rb and depth_virtual_test.rb
The depth-related test files exist but likely don't cover interactions between depth_caching_test.rb, depth_constraints_test.rb, and depth_virtual_test.rb. There are gaps testing what happens when depth constraints are violated, virtual depth is accessed on unsaved records, or counter caches are out of sync.
- [ ] Examine test/concerns/depth_constraints_test.rb, depth_caching_test.rb, and depth_virtual_test.rb for overlaps and gaps
- [ ] Add test cases for: constraint violations with virtual depth, counter cache behavior when constraints fail, deeply nested trees (10+ levels), and concurrent depth updates
- [ ] Add edge case tests in a new test/concerns/depth_integration_test.rb for cross-feature interactions
- [ ] Run full test suite to ensure no regressions
Document and add tests for ltree adapter PostgreSQL-specific behavior
lib/ancestry/ltree.rb provides PostgreSQL ltree support (a specialized tree type), but CONFIGURATION.md likely doesn't document ltree-specific setup, limitations, and migration requirements. Tests are probably missing for PostgreSQL-only features like custom operators and GiST indexing.
- [ ] Review lib/ancestry/ltree.rb to identify PostgreSQL-specific behavior and GiST index generation
- [ ] Add a new section to CONFIGURATION.md documenting: ltree adapter requirements, migration syntax for ltree columns, index strategy differences, and performance considerations vs materialized_path
- [ ] Create test/concerns/ltree_specific_test.rb with tests for: ltree operator queries, GiST index usage, migration generation, and handling of special ltree characters
- [ ] Add a GitHub Actions matrix step in .github/workflows/run_test_suite.yml that optionally runs PostgreSQL-only tests when available
🌿Good first issues
- Add integration tests in
test/for the real ActiveRecord associations feature (belongs_to :parent,has_many :children) mentioned in the README, specifically testing eager loading with.includes(:children)across different Rails versions in the Appraisals matrix. - Create a new Mermaid diagram and corresponding PNG in
img/documenting thecounter_cachebehavior (how child counts propagate up the tree whencounter_cache: true), following the style of existing diagrams likeimg/ancestors.mmd. - Write an example migration script in
examples/(or a newdoc/examples/folder) showing how to safely migrate an existing non-hierarchical table to use Ancestry, including a backfill strategy for the ancestry column and validation steps.
📝Recent commits
Click to expand
Recent commits
b0aa873— Merge pull request #763 from kbrock/check-no-db-at-load (kbrock)1c1ea51— Add rake check_no_db_at_load task (kbrock)f353de7— Merge pull request #762 from sdhull/docs-restore-generated-column-links (kbrock)117209b— Restore generated-column docs links and add version-tag note (sdhull)4641da6— Merge pull request #760 from kbrock/add-leaves-image (kbrock)c3b8eda— Add missing leaves diagram to navigation images (kbrock)86ebfbf— Merge pull request #758 from kbrock/adapter-module (kbrock)d893f6a— Adapter: absorb concat helper and mix into format modules (kbrock)06199c3— Add Ancestry::Adapter detection module (kbrock)4e532d2— Merge pull request #757 from kbrock/memoize-child-ancestry-sql (kbrock)
🔒Security observations
The ancestry gem appears to be a well-maintained ActiveRecord extension for tree structures. Primary security concerns revolve around SQL injection risks in materialized path query construction and lack of visible dependency vulnerability scanning. The codebase lacks a formal security policy. No obvious hardcoded secrets detected. The main risk is improper parameterization of SQL queries when constructing ancestry path filters. Dependency analysis is incomplete due to missing package file contents. Overall security posture is moderate with attention needed to query construction practices and dependency management.
- Medium · SQL Injection Risk in Materialized Path Pattern —
lib/ancestry/materialized_path.rb, lib/ancestry/materialized_path2.rb, lib/ancestry/materialized_path3.rb, lib/ancestry/materialized_path_array.rb. The ancestry gem implements materialized path pattern storing ancestor chains in a single column. Without proper parameterization of path queries, there could be SQL injection vulnerabilities when constructing WHERE clauses based on ancestry paths. The files lib/ancestry/materialized_path*.rb need careful review for raw SQL construction. Fix: Ensure all SQL queries use parameterized statements and ActiveRecord's query builder (e.g., where with placeholders ?). Never concatenate user input into SQL strings. Conduct thorough code review of query construction methods. - Low · Missing Dependency File —
Gemfile, gemfiles/*, ancestry.gemspec. The provided context shows 'Dependencies/Package file content:' is empty. The Gemfile and gemfiles directory exist but their contents were not provided for analysis. Unable to verify if dependencies have known vulnerabilities or if versions are pinned appropriately. Fix: Run 'bundle audit' or similar tools to check for known vulnerabilities in dependencies. Pin gem versions to specific patch releases. Review Gemfile.lock for security updates. - Low · No Security Policy or Disclosure Guidelines —
Repository root. While CODE_OF_CONDUCT.md exists, there is no visible SECURITY.md or security policy file that defines how security vulnerabilities should be reported responsibly. Fix: Create a SECURITY.md file documenting responsible disclosure process, contact information for security issues, and expected response timeline. - Low · Insufficient Input Validation in Tree Operations —
lib/ancestry/instance_methods.rb, lib/ancestry/instance_methods_builder.rb. The gem provides tree manipulation methods (parent assignment, ancestry updates) without clearly documented input validation requirements. User-supplied ancestry values could potentially bypass validation if not properly sanitized. Fix: Implement strict validation for ancestry column values. Use allow lists for permitted characters. Add comprehensive input validation tests. Document expected format for ancestry values.
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.