WARNING! THIS GEM IS NOT COMPATIBLE WITH ordered_tree gem.
Specify this acts_as
extension if you want to model an ordered tree structure (adjacency list hierarchical structure) by providing a parent association, a children association and a sort column. For proper use you should have a foreign key column, which by default is called parent_id
, and a sort column, which is by default called position
.
This extension is mostly compatible with awesome_nested_set
gem
Gem depends on active_record >= 3
. We test it with rails-3.0
, rails-3.1
, rails-3.2
and with ruby-1.9.3
, ruby-1.9.2
, ruby-1.8.7
, jruby-1.6.7
and rubinius-2.0
.
- Supports PostgreSQL recursive queries (requires at least
postgresql-8.3
) - Holds integrity control via pessimistic database locks. Common situation for
acts_as_list
users is non-unique positions within list. It happens when two concurrent users modify list sumultaneously.acts_as_ordered_tree
uses pessimistic locks to keep your tree consistent.
Install it via rubygems:
gem install acts_as_ordered_tree
To make use of acts_as_ordered_tree
, your model needs to have 2 fields: parent_id and position. You can also have an optional fields: depth
and children_count
:
class CreateCategories < ActiveRecord::Migration
def self.up
create_table :categories do |t|
t.integer :company_id
t.string :name
t.integer :parent_id # this is mandatory
t.integer :position # this is mandatory
t.integer :depth # this is optional
t.integer :children_count # this is optional
end
end
def self.down
drop_table :categories
end
end
Setup your model:
class Category < ActiveRecord::Base
acts_as_ordered_tree
# gem introduces new ActiveRecord callbacks:
# *_reorder - fires when position (but not parent node) is changed
# *_move - fires when parent node is changed
before_reorder :do_smth
before_move :do_smth_else
end
Now you can use acts_as_ordered_tree
features:
# root
# \_ child1
# \_ subchild1
# \_ subchild2
root = Category.create(:name => "root")
child1 = root.children.create(:name => "child1")
subchild1 = child1.children.create("name" => "subchild1")
subchild2 = child1.children.create("name" => "subchild2")
Category.roots # => [root]
root.root? # => true
root.parent # => nil
root.ancestors # => []
root.descendants # => [child1, subchild1, subchild2]
child1.parent # => root
child1.ancestors # => [root]
child1.children # => [subchild1, subchild2]
child1.descendants # => [subchild1, subchild2]
child1.root? # => false
child1.leaf? # => false
subchild1.ancestors # => [child1, root]
subchild1.root # => [root]
subchild1.leaf? # => true
subchild1.first? # => true
subchild1.last? # => false
subchild2.last? # => true
subchild1.move_to_above_of(child1)
subchild1.move_to_bottom_of(child1)
subchild1.move_to_child_of(root)
subchild1.move_lower
subchild1.move_higher
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Added some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
- Fix README typos and grammatical errors (english speaking contributors are welcomed)
- Add moar examples and docs.
- Implement converter from other structures (nested_set, closure_tree)