[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7809":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":18,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":24,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":16,"starSnapshotCount":16,"syncStatus":29,"lastSyncTime":30,"discoverSource":31},7809,"ancestry","stefankroes\u002Fancestry","stefankroes","Organise ActiveRecord model into a tree structure","",null,"Ruby",3874,472,45,22,0,1,3,17,30.02,"MIT License",false,"master",true,[],"2026-06-12 02:01:44","[![CI](https:\u002F\u002Fgithub.com\u002Fstefankroes\u002Fancestry\u002Factions\u002Fworkflows\u002Frun_test_suite.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fstefankroes\u002Fancestry\u002Factions\u002Fworkflows\u002Frun_test_suite.yml)\n\n# Ancestry\n\n> **Reading these docs on GitHub?** The `master` branch reflects bleeding-edge\n> development and may describe features not yet released. Use the branch\n> selector above to switch to the [tag](https:\u002F\u002Fgithub.com\u002Fstefankroes\u002Fancestry\u002Ftags)\n> matching the version of the gem you have installed.\n\n## Overview\n\nAncestry is a gem that allows rails ActiveRecord models to be organized as\na tree structure (or hierarchy). It employs the materialized path pattern —\none column, no extra tables, single-query reads. [Benchmarks](https:\u002F\u002Fgithub.com\u002Fkbrock\u002Ftree-bench)\nshow it outperforms alternatives on most single-node operations.\n\n# Features\n\nAncestry uses the **materialized path** pattern: each record stores its ancestor\nchain in a single column (e.g. `1\u002F2\u002F3\u002F`). No additional tables needed.\n\n- Single btree indexed query for [any relation](#tree-navigation): `ancestors`, `descendants`, `siblings`, `children`, `leaves`. [Benchmarks](https:\u002F\u002Fgithub.com\u002Fkbrock\u002Ftree-bench)\n- No extra tables — hierarchy lives in a column on your existing table\n- Moving a node only updates its descendants, not the whole tree\n- **New:** Real ActiveRecord [associations](#cached-columns) (`belongs_to :parent`, `has_many :children`) with eager loading\n- [Multiple orphan strategies](#has_ancestry-options) for handling deleted nodes\n- [Depth caching and constraints](#selecting-nodes-by-depth), counter caches\n- [Integrity checking and restoration](CONFIGURATION.md)\n- STI support — all classes returned from scopes unless filtered with `where(type: \"ChildClass\")`\n\n# Installation\n\nFollow these steps to apply Ancestry to any ActiveRecord model:\n\n```ruby\n# Gemfile\ngem 'ancestry'\n```\n\n```bash\n$ bundle install\n$ rails g migration add_ancestry_to_[table]\n```\n\n```ruby\nclass AddAncestryToTable \u003C ActiveRecord::Migration[7.0]\n  def change\n    change_table(:table) do |t|\n      t.ancestry\n      # t.ancestry format: :materialized_path3, cache_depth: true, parent: true, counter_cache: true\n    end\n  end\nend\n```\n\nThe `t.ancestry` helper creates the column with the correct type, collation, and indexes for your database. It accepts options for [cached columns](#cached-columns) and [ancestry formats](#ancestry-formats).\n\nFor manual column setup or advanced options, see [Ancestry Database Column](#ancestry-database-column).\n\n```bash\n$ rake db:migrate\n```\n\n## Configure ancestry defaults\n\n```ruby\n# config\u002Finitializers\u002Fancestry.rb (optional)\n\n# use the newer format\nAncestry.default_ancestry_format = :materialized_path3\n# Ancestry.default_update_strategy = :sql\n# Ancestry.primary_key_format = :uuid\n```\n\nYou can set some default ancestry options, or add them to each `has_ancestry` call in your models.\n\n## Add ancestry to your model\n\n```ruby\n# app\u002Fmodels\u002F[model.rb]\n\nclass [Model] \u003C ActiveRecord::Base\n   has_ancestry\nend\n```\n\nYour model is now a tree!\n\n# Organising records into a tree\n\nYou can use `parent_id` and `parent` to add a node into a tree. They can be\nset as attributes or passed into methods like `new`, `create`, and `update`.\n\n```ruby\nTreeNode.create! :name => 'Stinky', :parent => TreeNode.create!(:name => 'Squeeky')\n```\n\nChildren can be created through the children relation on a node: `node.children.create :name => 'Stinky'`.\n\n# Tree Navigation\n\nThe node with the large border is the reference node (the node from which the navigation method is invoked.)\nThe yellow nodes are those returned by the method.\n\n|                               |                                                     |                                 |                             |\n|:-:                            |:-:                                                  |:-:                              |:-:                          |\n|**parent**                     |**ancestors**                                        |**path**                         |**root**                     |\n|![parent](\u002Fimg\u002Fparent.png)     |![ancestors](\u002Fimg\u002Fancestors.png)                     |![path](\u002Fimg\u002Fpath.png)           |![root](\u002Fimg\u002Froot.png)       |\n| nil for a root node           | root..parent                                        | root..self                      | self for a root node        |\n| `parent_id`                   | `ancestor_ids`                                      | `path_ids`                      | `root_id`                   |\n| `has_parent?`                 |                                                     |                                 | `is_root?`                  |\n| `parent_of?`                  | `ancestor_of?`                                      |                                 | `root_of?`                  |\n|**children**                   |**descendants**                                      |**subtree**                      |**leaves**                   |\n|![children](\u002Fimg\u002Fchildren.png) |![descendants](\u002Fimg\u002Fdescendants.png)                 |![subtree](\u002Fimg\u002Fsubtree.png)     |![leaves](\u002Fimg\u002Fleaves.png)   |\n| direct children               | all below                                           | self + descendants              | descendants with no children|\n| `child_ids`                   | `descendant_ids`                                    | `subtree_ids`                   | `leaf_ids`                  |\n| `has_children?`               |                                                     |                                 | `is_leaf?`                  |\n| `child_of?`                   | `descendant_of?`                                    | `in_subtree_of?`                |                             |\n|**siblings**\u003Csup>\u003Ca href=\"#fn1\" id=\"ref1\">1\u003C\u002Fa>\u003C\u002Fsup>                                |**indirects**                    |                             |\n|![siblings](\u002Fimg\u002Fsiblings.png) |![indirects](\u002Fimg\u002Findirects.png)                     |                                 |                             |\n| excludes self                 | descendants - children                              |                                 |                             |\n| `sibling_ids`                 | `indirect_ids`                                      |                                 |                             |\n| `has_siblings?`               |                                                     |                                 |                             |\n| `sibling_of?`                 | `indirect_of?`                                      |                                 |                             |\n\nWhen using `STI` all classes are returned from the scopes unless you specify otherwise using `where(:type => \"ChildClass\")`.\n\n\u003Csup id=\"fn1\">1. [root nodes are siblings of each other]\u003Ca href=\"#ref1\" title=\"Jump back to footnote 1.\">↩\u003C\u002Fa>\u003C\u002Fsup>\n\n# has_ancestry options\n\nThe `has_ancestry` method supports the following options:\n\n    :ancestry_column       Column name to store ancestry\n                           'ancestry' (default)\n    :ancestry_format       Format for ancestry column (see Ancestry Formats section):\n                           :materialized_path   1\u002F2\u002F3, root nodes ancestry=nil (default)\n                           :materialized_path2  \u002F1\u002F2\u002F3\u002F, root nodes ancestry=\u002F (preferred)\n                           :ltree               1.2.3, root nodes ancestry='' (PostgreSQL only)\n                           :array               {1,2,3}, root nodes ancestry={} (PostgreSQL only)\n    :orphan_strategy       How to handle children of a destroyed node:\n                           :destroy   All children are destroyed as well (default)\n                           :rootify   The children of the destroyed node become root nodes\n                           :restrict  An AncestryException is raised if any children exist\n                           :adopt     The orphan subtree is added to the parent of the deleted node\n                                      If the deleted node is Root, then rootify the orphan subtree\n                           :none      skip this logic. (add your own `before_destroy`)\n    :cache_depth           Cache the depth (number of ancestors) in a column: (See Cached Columns)\n                           false    Do not cache depth (default)\n                           true     Cache depth in 'ancestry_depth'\n                           :virtual Use a database generated column\n                           String   Cache depth in the column referenced\n    :parent                Store the parent id in a column: (See Cached Columns)\n                           false    Do not store parent id (default)\n                           true     Cache parent id in 'parent_id' and define\n                                    belongs_to :parent and has_many :children associations\n                           :virtual Use a database generated column with associations\n    :root                  Store the root id in a column: (See Cached Columns)\n                           false    Do not store root id (default)\n                           true     Cache root id in 'root_id' and define\n                                    belongs_to :root association\n                           :virtual Use a database generated column with association\n    :primary_key_format    Format of the primary key:\n                           :integer  integer ids (default)\n                           :uuid     UUIDs\n                           :string   alphanumeric string ids\n    :touch                 Touch the ancestors of a node when it changes:\n                           false  don't invalid nested key-based caches (default)\n                           true   touch all ancestors of previous and new parents\n    :counter_cache         Cache the number of children in a column:\n                           false  Do not cache child count (default)\n                           true   Cache child count in 'children_count'\n                           String Cache child count in the column referenced\n    :update_strategy       How to update descendants nodes:\n                           :ruby  All descendants are updated using the ruby algorithm. (default)\n                                  This triggers update callbacks for each descendant node\n                           :sql   All descendants are updated using a single SQL statement.\n                                  This strategy does not trigger update callbacks for the descendants.\n                                  This strategy is available only for PostgreSql implementations\n\nLegacy configuration using `acts_as_tree` is still available. Ancestry defers to `acts_as_tree` if that gem is installed.\n\n# (Named) Scopes\n\nThe navigation methods return scopes instead of records, where possible. Additional ordering,\nconditions, limits, etc. can be applied and the results can be retrieved, counted, or checked for existence:\n\n```ruby\nnode.children.where(:name => 'Mary').exists?\nnode.subtree.order(:name).limit(10).each { ... }\nnode.descendants.count\n```\n\nA couple of class-level named scopes are included:\n\n    roots                   Root nodes\n    ancestors_of(node)      Ancestors of node, node can be either a record or an id\n    children_of(node)       Children of node, node can be either a record or an id\n    descendants_of(node)    Descendants of node, node can be either a record or an id\n    indirects_of(node)      Indirect children of node, node can be either a record or an id\n    subtree_of(node)        Subtree of node, node can be either a record or an id\n    siblings_of(node)       Siblings of node, node can be either a record or an id\n\nIt is possible thanks to some convenient rails magic to create nodes through the children and siblings scopes:\n\n    node.children.create\n    node.siblings.create!\n    TestNode.children_of(node_id).new\n    TestNode.siblings_of(node_id).create\n\n# Selecting nodes by depth\n\nWith depth caching enabled (see [has_ancestry options](#has_ancestry-options)), an additional five named\nscopes can be used to select nodes by depth:\n\n    before_depth(depth)     Return nodes that are less deep than depth (node.depth \u003C depth)\n    to_depth(depth)         Return nodes up to a certain depth (node.depth \u003C= depth)\n    at_depth(depth)         Return nodes that are at depth (node.depth == depth)\n    from_depth(depth)       Return nodes starting from a certain depth (node.depth >= depth)\n    after_depth(depth)      Return nodes that are deeper than depth (node.depth > depth)\n\nDepth scopes are also available through calls to `descendants`,\n`descendant_ids`, `subtree`, `subtree_ids`, `path` and `ancestors` (with relative depth).\nNote that depth constraints cannot be passed to `ancestor_ids` or `path_ids` as both relations\ncan be fetched directly from the ancestry column without needing a query. Use\n`ancestors(depth_options).map(&:id)` or `ancestor_ids.slice(min_depth..max_depth)` instead.\n\n    node.ancestors(:from_depth => -6, :to_depth => -4)\n    node.path.from_depth(3).to_depth(4)\n    node.descendants(:from_depth => 2, :to_depth => 4)\n    node.subtree.from_depth(10).to_depth(12)\n\n# Arrangement\n\n## `arrange`\n\nA subtree can be arranged into nested hashes for easy navigation after database retrieval.\n\nThe resulting format is a hash of hashes\n\n```ruby\n{\n  #\u003CTreeNode id: 100018, name: \"Stinky\", ancestry: nil> => {\n    #\u003CTreeNode id: 100019, name: \"Crunchy\", ancestry: \"100018\"> => {\n      #\u003CTreeNode id: 100020, name: \"Squeeky\", ancestry: \"100018\u002F100019\"> => {}\n    },\n    #\u003CTreeNode id: 100021, name: \"Squishy\", ancestry: \"100018\"> => {}\n  }\n}\n```\n\nThere are many ways to call `arrange`:\n\n```ruby\nTreeNode.find_by(:name => 'Crunchy').subtree.arrange\nTreeNode.find_by(:name => 'Crunchy').subtree.arrange(:order => :name)\n```\n\n## `arrange_serializable`\n\nIf a hash of arrays is preferred, `arrange_serializable` can be used. The results\nwork well with `to_json`.\n\n```ruby\nTreeNode.arrange_serializable(:order => :name)\n# use an active model serializer\nTreeNode.arrange_serializable { |parent, children| MySerializer.new(parent, children: children) }\nTreeNode.arrange_serializable do |parent, children|\n  {\n     my_id: parent.id,\n     my_children: children\n  }\nend\n```\n\n# Sorting\n\nThe `sort_by_ancestry` class method: `TreeNode.sort_by_ancestry(array_of_nodes)` can be used\nto sort an array of nodes as if traversing in preorder. (Note that since materialized path\ntrees do not support ordering within a rank, the order of siblings is\ndependant upon their original array order.)\n\n\n# Ancestry Database Column\n\nThe `t.ancestry` migration helper handles column type, collation, and indexes automatically.\nFor most applications, `t.ancestry` is all you need.\n\nFor manual column setup, database-specific collation options, and migrating collation on\nexisting columns, see [Configuration Reference](CONFIGURATION.md).\n\n# Ancestry Formats\n\nYou can choose from the following ancestry formats:\n\n- `:materialized_path` - legacy format (default for backwards compatibility)\n- `:materialized_path2` - recommended for new columns\n- `:materialized_path3` - like mp2 but root is `\"\"` instead of `\"\u002F\"`\n- `:ltree` - PostgreSQL ltree type with GiST indexing\n\nIf you are unsure, choose `:materialized_path2`. It allows a `NOT NULL` column and\nfaster descendant queries (one less `OR` condition).\n\nFor PostgreSQL users who want native indexing, `:ltree` avoids string\nparsing and collation issues entirely:\n\n```ruby\n# ltree — GiST-indexed \u003C@ operator\nenable_extension 'ltree'\ncreate_table :tree_nodes do |t|\n  t.ancestry format: :ltree\nend\n```\n\nFor detailed format comparison, migration between formats, and database-specific\ncolumn options, see [Configuration Reference](CONFIGURATION.md#ancestry-formats).\n\n# Supported Rails Versions\n\n| Ancestry | Rails              |\n|----------|---------------------|\n| 2.x      | 4.1 and earlier     |\n| 3.x      | 4.2 – 5.0          |\n| 4.x      | 5.2 – 7.0          |\n| 5.x      | 6.0 – 8.1          |\n| 6.x      | 7.0 – 8.1          |\n\n# Running Tests\n\n```bash\ngit clone git@github.com:stefankroes\u002Fancestry.git\ncd ancestry\ncp test\u002Fdatabase.example.yml test\u002Fdatabase.yml\nbundle\nappraisal install\n# all tests\nappraisal rake test\n# single test version (sqlite and rails 5.0)\nappraisal sqlite3-ar-50 rake test\n```\n\n# See also\n\nOther Ruby tree gems, each with different tradeoffs:\n\n- [acts_as_list](https:\u002F\u002Fgithub.com\u002Fbrendon\u002Facts_as_list) — sortable lists with position column\n- [acts_as_tree](https:\u002F\u002Fgithub.com\u002Famerine\u002Facts_as_tree) — simple adjacency list (parent_id only)\n- [awesome_nested_set](https:\u002F\u002Fgithub.com\u002Fcollectiveidea\u002Fawesome_nested_set) — nested set pattern (lft\u002Frgt columns), fast subtree queries\n- [closure_tree](https:\u002F\u002Fgithub.com\u002FClosureTree\u002Fclosure_tree) — closure table pattern (separate hierarchy table), fast reads\n- [ltree_hierarchy](https:\u002F\u002Fgithub.com\u002Fcfabianski\u002Fltree_hierarchy) - Postgres ltree implementation\n- [parentry](https:\u002F\u002Fgithub.com\u002Fhasghari\u002Fparentry) - ltree and array implementation of ancestry.\n- [pg_ltree](https:\u002F\u002Fgithub.com\u002Fsjke\u002Fpg_ltree) - Postgres ltree implementation\n\n# Contributing and license\n\nQuestion? Bug report? Faulty\u002Fincomplete documentation? Feature request? Please\npost an issue on 'http:\u002F\u002Fgithub.com\u002Fstefankroes\u002Fancestry\u002Fissues'. Make sure\nyou have read the documentation and you have included tests and documentation\nwith any pull request.\n\nCopyright (c) 2016 Stefan Kroes, released under the MIT license\n","Ancestry 是一个 Ruby gem，用于将 Rails 的 ActiveRecord 模型组织成树状结构。它采用了物化路径模式，通过单一列存储祖先链，无需额外的表，单次查询即可读取。这使得 Ancestry 在大多数单节点操作中表现出色。项目支持单个 B-Tree 索引查询来获取各种关系（如祖先、后代、兄弟节点等），并且在移动节点时仅更新其后代而非整个树。此外，它还提供了多种处理删除节点的策略、深度缓存与约束等功能，并支持 STI（单表继承）。Ancestry 适用于需要高效管理和查询层次结构数据的应用场景，例如组织机构图、分类系统等。",2,"2026-06-11 03:14:31","top_language"]