{"id":13462911,"url":"https://github.com/collectiveidea/awesome_nested_set","last_synced_at":"2026-10-19T08:42:22.215Z","repository":{"id":383723,"uuid":"912","full_name":"collectiveidea/awesome_nested_set","owner":"collectiveidea","description":"An awesome replacement for acts_as_nested_set and better_nested_set.","archived":false,"fork":false,"pushed_at":"2026-04-27T18:46:21.000Z","size":683,"stargazers_count":2410,"open_issues_count":3,"forks_count":488,"subscribers_count":37,"default_branch":"main","last_synced_at":"2026-10-13T05:25:28.228Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/collectiveidea.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["parndt"]}},"created_at":"2008-02-21T16:03:25.000Z","updated_at":"2026-09-02T08:28:10.000Z","dependencies_parsed_at":"2023-07-05T14:43:48.822Z","dependency_job_id":"d237eec4-3b4d-49da-9074-9130813ef627","html_url":"https://github.com/collectiveidea/awesome_nested_set","commit_stats":{"total_commits":486,"total_committers":139,"mean_commits":"3.4964028776978417","dds":0.8395061728395061,"last_synced_commit":"3913eca5981ec60662985fe39adf988eb5c2731d"},"previous_names":[],"tags_count":46,"template":false,"template_full_name":null,"purl":"pkg:github/collectiveidea/awesome_nested_set","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collectiveidea%2Fawesome_nested_set","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collectiveidea%2Fawesome_nested_set/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collectiveidea%2Fawesome_nested_set/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collectiveidea%2Fawesome_nested_set/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/collectiveidea","download_url":"https://codeload.github.com/collectiveidea/awesome_nested_set/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/collectiveidea%2Fawesome_nested_set/sbom","scorecard":{"id":300172,"data":{"date":"2025-08-11","repo":{"name":"github.com/collectiveidea/awesome_nested_set","commit":"3d321417b6c288f26a598de6a0f64cde1192b489"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":6,"reason":"Found 15/25 approved changesets -- score normalized to 6","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: jobLevel 'contents' permission set to 'write': .github/workflows/publish_gem.yml:15","Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Warn: no topLevel permission defined: .github/workflows/publish_gem.yml:1"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:344: update your workflow using https://app.stepsecurity.io/secureworkflow/collectiveidea/awesome_nested_set/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:346: update your workflow using https://app.stepsecurity.io/secureworkflow/collectiveidea/awesome_nested_set/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:104: update your workflow using https://app.stepsecurity.io/secureworkflow/collectiveidea/awesome_nested_set/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:106: update your workflow using https://app.stepsecurity.io/secureworkflow/collectiveidea/awesome_nested_set/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:223: update your workflow using https://app.stepsecurity.io/secureworkflow/collectiveidea/awesome_nested_set/ci.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/ci.yml:225: update your workflow using https://app.stepsecurity.io/secureworkflow/collectiveidea/awesome_nested_set/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish_gem.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/collectiveidea/awesome_nested_set/publish_gem.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish_gem.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/collectiveidea/awesome_nested_set/publish_gem.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish_gem.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/collectiveidea/awesome_nested_set/publish_gem.yml/main?enable=pin","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   5 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: MIT-LICENSE:0","Info: FSF or OSI recognized license: MIT License: MIT-LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v3.7.0 not signed: https://api.github.com/repos/collectiveidea/awesome_nested_set/releases/172445457","Warn: release artifact v3.6.0 not signed: https://api.github.com/repos/collectiveidea/awesome_nested_set/releases/172445762","Warn: release artifact v3.5.0 not signed: https://api.github.com/repos/collectiveidea/awesome_nested_set/releases/59057301","Warn: release artifact v3.1.1 not signed: https://api.github.com/repos/collectiveidea/awesome_nested_set/releases/3343835","Warn: release artifact v3.7.0 does not have provenance: https://api.github.com/repos/collectiveidea/awesome_nested_set/releases/172445457","Warn: release artifact v3.6.0 does not have provenance: https://api.github.com/repos/collectiveidea/awesome_nested_set/releases/172445762","Warn: release artifact v3.5.0 does not have provenance: https://api.github.com/repos/collectiveidea/awesome_nested_set/releases/59057301","Warn: release artifact v3.1.1 does not have provenance: https://api.github.com/repos/collectiveidea/awesome_nested_set/releases/3343835"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 20 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T20:24:14.922Z","repository_id":383723,"created_at":"2025-08-17T20:24:14.922Z","updated_at":"2025-08-17T20:24:14.922Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":344872684,"owners_count":38352845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-10-03T21:59:58.778Z","status":"online","status_checked_at":"2026-10-19T02:00:06.414Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T13:00:40.780Z","updated_at":"2026-10-19T08:42:21.958Z","avatar_url":"https://github.com/collectiveidea.png","language":"Ruby","funding_links":["https://github.com/sponsors/parndt"],"categories":["Active Record Plugins","Ruby","ORM/ODM Extensions","📦 Miscellaneous","Gems"],"sub_categories":["Active Record Nesting","🏆 Top 25","Attributes Management"],"readme":"# Awesome Nested Set\n\n[![CI](https://github.com/collectiveidea/awesome_nested_set/actions/workflows/ci.yml/badge.svg)](https://github.com/collectiveidea/awesome_nested_set/actions/workflows/ci.yml) [![Code Climate](https://codeclimate.com/github/collectiveidea/awesome_nested_set.svg)](https://codeclimate.com/github/collectiveidea/awesome_nested_set)\n\n\nAwesome Nested Set is an implementation of the nested set pattern for ActiveRecord models.\nIt is a replacement for acts_as_nested_set and BetterNestedSet, but more awesome.\n\nOlder versions: Version 3.2 supports Rails 6, 3.1 supports Rails 5 \u0026 4. Version 2 supports Rails 3. \nGem versions prior to 2.0 support Rails 2.\n\n## What makes this so awesome?\n\nThis is a new implementation of nested set based off of BetterNestedSet that fixes some bugs, removes tons of duplication, adds a few useful methods, and adds STI support.\n\n\n## Installation\n\nAdd to your Gemfile:\n\n```ruby\ngem 'awesome_nested_set'\n```\n\n## Usage\n\nTo make use of `awesome_nested_set` your model needs to have 3 fields:\n`lft`, `rgt`, and `parent_id`. The names of these fields are configurable.\nYou can also have optional fields: `depth` and `children_count`. These fields are configurable.\nNote that the `children_count` column must have `null: false` and `default: 0` to\nfunction properly.\n\n```ruby\nclass CreateCategories \u003c ActiveRecord::Migration\n  def change\n    create_table :categories do |t|\n      t.string :name\n      t.integer :parent_id, null: true, index: true\n      t.integer :lft, null: false, index: true\n      t.integer :rgt, null: false, index: true\n\n      # optional fields\n      t.integer :depth, null: false, default: 0\n      t.integer :children_count, null: false, default: 0\n      t.timestamps\n    end\n  end\nend\n```\n\nEnable the nested set functionality by declaring `acts_as_nested_set` on your model\n\n```ruby\nclass Category \u003c ActiveRecord::Base\n  acts_as_nested_set\nend\n```\n\nRun `rake rdoc` to generate the API docs and see [CollectiveIdea::Acts::NestedSet](lib/awesome_nested_set/awesome_nested_set.rb) for more information.\n\n## Options\n\nYou can pass various options to `acts_as_nested_set` macro. Configuration options are:\n\n* `parent_column`: specifies the column name to use for keeping the position integer (default: parent_id)\n* `primary_column`: specifies the column name to use as the inverse of the parent column (default: id)\n* `left_column`: column name for left boundary data (default: lft)\n* `right_column`: column name for right boundary data (default: rgt)\n* `depth_column`: column name for the depth data default (default: depth)\n* `scope`: restricts what is to be considered a list. Given a symbol, it'll attach `_id` (if it hasn't been already) and use that as the foreign key restriction. You can also pass an array to scope by multiple attributes. Example: `acts_as_nested_set :scope =\u003e [:notable_id, :notable_type]`\n* `dependent`: behavior for cascading destroy. If set to :destroy, all the child objects are destroyed alongside this object by calling their destroy method. If set to :delete_all (default), all the child objects are deleted without calling their destroy method. If set to :nullify, all child objects will become orphaned and become roots themselves.\n* `counter_cache`: adds a counter cache for the number of children. defaults to false. Example: `acts_as_nested_set :counter_cache =\u003e :children_count`\n* `order_column`: on which column to do sorting, by default it is the left_column_name. Example: `acts_as_nested_set :order_column =\u003e :position`\n* `touch`: If set to `true`, then the updated_at timestamp on the ancestors will be set to the current time whenever this object is saved or destroyed (default: false)\n\nSee [CollectiveIdea::Acts::NestedSet::Model::ClassMethods](/lib/awesome_nested_set/model.rb#L26) for a list of class methods and [CollectiveIdea::Acts::NestedSet::Model](lib/awesome_nested_set/model.rb#L13) for a list of instance methods added to acts_as_nested_set models\n\n## Indexes\n\nIt is highly recommended that you add an index to the `rgt` column on your models. Every insertion requires finding the next `rgt` value to use and this can be slow for large tables without an index. It is probably best to index the other fields as well (`parent_id`, `lft`, `depth`).\n\n## Callbacks\n\nThere are three callbacks called when moving a node:\n`before_move`, `after_move` and `around_move`.\n\n```ruby\nclass Category \u003c ActiveRecord::Base\n  acts_as_nested_set\n\n  after_move :rebuild_slug\n  around_move :da_fancy_things_around\n\n  private\n\n  def rebuild_slug\n    # do whatever\n  end\n\n  def da_fancy_things_around\n    # do something...\n    yield # actually moves\n    # do something else...\n  end\nend\n```\n\nBeside this there are also hooks to act on the newly added or removed children.\n\n```ruby\nclass Category \u003c ActiveRecord::Base\n  acts_as_nested_set  :before_add     =\u003e :do_before_add_stuff,\n                      :after_add      =\u003e :do_after_add_stuff,\n                      :before_remove  =\u003e :do_before_remove_stuff,\n                      :after_remove   =\u003e :do_after_remove_stuff\n\n  private\n\n  def do_before_add_stuff(child_node)\n    # do whatever with the child\n  end\n\n  def do_after_add_stuff(child_node)\n    # do whatever with the child\n  end\n\n  def do_before_remove_stuff(child_node)\n    # do whatever with the child\n  end\n\n  def do_after_remove_stuff(child_node)\n    # do whatever with the child\n  end\nend\n```\n\n## Protecting attributes from mass assignment (for Rails \u003c 4)\n\nIt's generally best to \"whitelist\" the attributes that can be used in mass assignment:\n\n```ruby\nclass Category \u003c ActiveRecord::Base\n  acts_as_nested_set\n  attr_accessible :name, :parent_id\nend\n```\n\nIf for some reason that is not possible, you will probably want to protect the `lft` and `rgt` attributes:\n\n```ruby\nclass Category \u003c ActiveRecord::Base\n  acts_as_nested_set\n  attr_protected :lft, :rgt\nend\n```\n\n\n## Add to your existing project\n\nTo make use of `awesome_nested_set`, your model needs to have 3 fields:\n`lft`, `rgt`, and `parent_id`. The names of these fields are configurable.\nYou can also have optional fields, `depth` and `children_count`.\n\nCreate a migration to add fields:\n\n```ruby\nclass AddNestedToCategories \u003c ActiveRecord::Migration\n\n  def self.up\n    add_column :categories, :parent_id, :integer # Comment this line if your project already has this column\n    # Category.where(parent_id: 0).update_all(parent_id: nil) # Uncomment this line if your project already has :parent_id\n    add_column :categories, :lft,       :integer\n    add_column :categories, :rgt,       :integer\n\n    # optional fields\n    add_column :categories, :depth,          :integer\n    add_column :categories, :children_count, :integer\n\n    # This is necessary to update :lft and :rgt columns\n    Category.reset_column_information\n    Category.rebuild!\n  end\n\n  def self.down\n    remove_column :categories, :parent_id\n    remove_column :categories, :lft\n    remove_column :categories, :rgt\n\n    # optional fields\n    remove_column :categories, :depth\n    remove_column :categories, :children_count\n  end\n\nend\n```\n\nEnable the nested set functionality by declaring `acts_as_nested_set` on your model\n\n```ruby\nclass Category \u003c ActiveRecord::Base\n  acts_as_nested_set\nend\n```\n\nYour project is now ready to run with the `awesome_nested_set` gem!\n\n\n## Conversion from other trees\n\nComing from acts_as_tree or another system where you only have a parent_id? No problem. Simply add the lft \u0026 rgt fields as above, and then run:\n\n```ruby\nCategory.rebuild!\n```\n\nYour tree will be converted to a valid nested set. Awesome!\n\nNote: You can use `Category.rebuild!(false)` to skip model validations when performing the rebuild.\n\n## View Helper\n\nThe view helper is called #nested_set_options.\n\nExample usage:\n\n```erb\n\u003c%= f.select :parent_id, nested_set_options(Category, @category) {|i| \"#{'-' * i.level} #{i.name}\" } %\u003e\n\n\u003c%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i| \"#{'-' * i.level} #{i.name}\" } ) %\u003e\n```\n\nSee [CollectiveIdea::Acts::NestedSet::Helper](lib/awesome_nested_set/helper.rb) for more information about the helpers.\n\n## How to contribute\n\nPlease see the ['Contributing' document](CONTRIBUTING.md).\n\nCopyright © 2008–2015 [Collective Idea](http://collectiveidea.com), released under the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcollectiveidea%2Fawesome_nested_set","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcollectiveidea%2Fawesome_nested_set","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcollectiveidea%2Fawesome_nested_set/lists"}