Module: Hierarchy
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/hierarchy.rb,
lib/hierarchy/node.rb,
lib/hierarchy/index_path.rb
Overview
Adds a tree structure to a model. This is very similar to ‘acts_as_nested_set` but uses the PostgreSQL-specific `ltree` feature for schema storage.
Your model must have a ‘path` field of type `ltree`. This field will be a period-delimited list of IDs of records above this one in the hierarchy. In addition, you should also consider the following indexes:
““ sql CREATE INDEX index1 ON table USING gist(path) CREATE INDEX index2 ON table USING btree(path) ““
replacing ‘table` with your table and `index1`/`index2` with appropriate names for these indexes.
Defined Under Namespace
Modules: ClassMethods Classes: IndexPath, Node
Instance Method Summary collapse
-
#ancestors(options = {}) ⇒ Array
Returns an array of ancestors above this object.
-
#bottom_level? ⇒ true, false
Whether or not this object has no children.
-
#children ⇒ ActiveRecord::Relation
The objects directly below this one in the hierarchy.
-
#descendants ⇒ ActiveRecord::Relation
The objects below this one in the hierarchy.
- #index_path ⇒ Object
- #my_path ⇒ Object
-
#parent ⇒ ActiveRecord::Base
The object directly above this one in the hierarchy.
-
#parent=(parent) ⇒ Object
Sets the object above this one in the hierarchy.
-
#root ⇒ Object
Root parent or nil(if current obj is top level).
-
#siblings ⇒ Array
The objects at the same hierarchical level of this one.
-
#top_level? ⇒ true, false
Whether or not this object has no parents.
Instance Method Details
#ancestors(options = {}) ⇒ Array
Returns an array of ancestors above this object. Note that a) this array is ordered with the most senior ancestor at the beginning of the list, and b) this is an array, not a relation. For that reason, you can pass any additional scope options to the method.
86 87 88 89 90 91 92 |
# File 'lib/hierarchy.rb', line 86 def ancestors(={}) @ancestors ||= begin return [] if top_level? objects = self.class.ancestors_of(self).scoped().group_by(&:id) index_path.map { |id| objects[id].first } end end |
#bottom_level? ⇒ true, false
Returns Whether or not this object has no children. Makes a database call.
135 136 137 |
# File 'lib/hierarchy.rb', line 135 def bottom_level? children.empty? end |
#children ⇒ ActiveRecord::Relation
Returns The objects directly below this one in the hierarchy.
111 112 113 |
# File 'lib/hierarchy.rb', line 111 def children self.class.children_of self end |
#descendants ⇒ ActiveRecord::Relation
Returns The objects below this one in the hierarchy.
97 98 99 |
# File 'lib/hierarchy.rb', line 97 def descendants self.class.descendants_of self end |
#index_path ⇒ Object
145 146 147 |
# File 'lib/hierarchy.rb', line 145 def index_path @index_path ||= IndexPath.from_ltree path.to_s end |
#my_path ⇒ Object
140 141 142 |
# File 'lib/hierarchy.rb', line 140 def my_path path.blank? ? id.to_s : "#{path}.#{id}" end |
#parent ⇒ ActiveRecord::Base
Returns The object directly above this one in the hierarchy.
104 105 106 |
# File 'lib/hierarchy.rb', line 104 def parent top_level? ? nil : self.class.parent_of(self).first end |
#parent=(parent) ⇒ Object
Sets the object above this one in the hierarchy.
73 74 75 76 |
# File 'lib/hierarchy.rb', line 73 def parent=(parent) raise ArgumentError, "Parent cannot be a new record" if parent.try(:new_record?) self.path = parent.try(:my_path) end |
#root ⇒ Object
Returns root parent or nil(if current obj is top level).
128 129 130 |
# File 'lib/hierarchy.rb', line 128 def root self.top_level? ? nil : self.class.find(self.path.split('.').first) end |
#siblings ⇒ Array
Returns The objects at the same hierarchical level of this one.
117 118 119 |
# File 'lib/hierarchy.rb', line 117 def siblings self.class.siblings_of(self) - [ self ] end |
#top_level? ⇒ true, false
Returns Whether or not this object has no parents.
123 124 125 |
# File 'lib/hierarchy.rb', line 123 def top_level? path.blank? end |