Module: Ancestry::InstanceMethods
- Defined in:
- lib/ancestry/instance_methods.rb
Instance Method Summary collapse
- #ancestor_conditions ⇒ Object
-
#ancestor_ids ⇒ Object
Ancestors.
- #ancestors(depth_options = {}) ⇒ Object
- #ancestry_callbacks_disabled? ⇒ Boolean
-
#ancestry_exclude_self ⇒ Object
Validate that the ancestors don’t include itself.
-
#apply_orphan_strategy ⇒ Object
Apply orphan strategy.
- #cache_depth ⇒ Object
-
#child_ancestry ⇒ Object
The ancestry value for this record’s children.
-
#child_conditions ⇒ Object
Children.
- #child_ids ⇒ Object
- #children ⇒ Object
- #depth ⇒ Object
-
#descendant_conditions ⇒ Object
Descendants.
- #descendant_ids(depth_options = {}) ⇒ Object
- #descendants(depth_options = {}) ⇒ Object
- #has_children? ⇒ Boolean
- #has_siblings? ⇒ Boolean
- #is_childless? ⇒ Boolean
- #is_only_child? ⇒ Boolean
- #is_root? ⇒ Boolean
- #parent ⇒ Object
-
#parent=(parent) ⇒ Object
Parent.
- #parent_id ⇒ Object
- #parent_id=(parent_id) ⇒ Object
- #path(depth_options = {}) ⇒ Object
- #path_conditions ⇒ Object
- #path_ids ⇒ Object
- #root ⇒ Object
-
#root_id ⇒ Object
Root.
-
#sibling_conditions ⇒ Object
Siblings.
- #sibling_ids ⇒ Object
- #siblings ⇒ Object
- #subtree(depth_options = {}) ⇒ Object
-
#subtree_conditions ⇒ Object
Subtree.
- #subtree_ids(depth_options = {}) ⇒ Object
-
#update_descendants_with_new_ancestry ⇒ Object
Update descendants with new ancestry.
-
#without_ancestry_callbacks ⇒ Object
Callback disabling.
Instance Method Details
#ancestor_conditions ⇒ Object
72 73 74 |
# File 'lib/ancestry/instance_methods.rb', line 72 def ancestor_conditions {self.base_class.primary_key => ancestor_ids} end |
#ancestor_ids ⇒ Object
Ancestors
68 69 70 |
# File 'lib/ancestry/instance_methods.rb', line 68 def ancestor_ids read_attribute(self.base_class.ancestry_column).to_s.split('/').map { |id| cast_primary_key(id) } end |
#ancestors(depth_options = {}) ⇒ Object
76 77 78 |
# File 'lib/ancestry/instance_methods.rb', line 76 def ancestors = {} self.base_class.scope_depth(, depth).ordered_by_ancestry.scoped :conditions => ancestor_conditions end |
#ancestry_callbacks_disabled? ⇒ Boolean
205 206 207 |
# File 'lib/ancestry/instance_methods.rb', line 205 def ancestry_callbacks_disabled? !!@disable_ancestry_callbacks end |
#ancestry_exclude_self ⇒ Object
Validate that the ancestors don’t include itself
4 5 6 |
# File 'lib/ancestry/instance_methods.rb', line 4 def ancestry_exclude_self add_error_to_base "#{self.class.name.humanize} cannot be a descendant of itself." if ancestor_ids.include? self.id end |
#apply_orphan_strategy ⇒ Object
Apply orphan strategy
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/ancestry/instance_methods.rb', line 32 def apply_orphan_strategy # Skip this if callbacks are disabled unless ancestry_callbacks_disabled? # If this isn't a new record ... unless new_record? # ... make al children root if orphan strategy is rootify if self.base_class.orphan_strategy == :rootify descendants.each do |descendant| descendant.without_ancestry_callbacks do descendant.update_attribute descendant.class.ancestry_column, (if descendant.ancestry == child_ancestry then nil else descendant.ancestry.gsub(/^#{child_ancestry}\//, '') end) end end # ... destroy all descendants if orphan strategy is destroy elsif self.base_class.orphan_strategy == :destroy descendants.all.each do |descendant| descendant.without_ancestry_callbacks do descendant.destroy end end # ... throw an exception if it has children and orphan strategy is restrict elsif self.base_class.orphan_strategy == :restrict raise Ancestry::AncestryException.new('Cannot delete record because it has descendants.') unless is_childless? end end end end |
#cache_depth ⇒ Object
96 97 98 |
# File 'lib/ancestry/instance_methods.rb', line 96 def cache_depth write_attribute self.base_class.depth_cache_column, depth end |
#child_ancestry ⇒ Object
The ancestry value for this record’s children
60 61 62 63 64 65 |
# File 'lib/ancestry/instance_methods.rb', line 60 def child_ancestry # New records cannot have children raise Ancestry::AncestryException.new('No child ancestry for new record. Save record before performing tree operations.') if new_record? if self.send("#{self.base_class.ancestry_column}_was").blank? then id.to_s else "#{self.send "#{self.base_class.ancestry_column}_was"}/#{id}" end end |
#child_conditions ⇒ Object
Children
131 132 133 |
# File 'lib/ancestry/instance_methods.rb', line 131 def child_conditions {self.base_class.ancestry_column => child_ancestry} end |
#child_ids ⇒ Object
139 140 141 |
# File 'lib/ancestry/instance_methods.rb', line 139 def child_ids children.all(:select => self.base_class.primary_key).map(&self.base_class.primary_key.to_sym) end |
#children ⇒ Object
135 136 137 |
# File 'lib/ancestry/instance_methods.rb', line 135 def children self.base_class.scoped :conditions => child_conditions end |
#depth ⇒ Object
92 93 94 |
# File 'lib/ancestry/instance_methods.rb', line 92 def depth ancestor_ids.size end |
#descendant_conditions ⇒ Object
Descendants
173 174 175 |
# File 'lib/ancestry/instance_methods.rb', line 173 def descendant_conditions ["#{self.base_class.ancestry_column} like ? or #{self.base_class.ancestry_column} = ?", "#{child_ancestry}/%", child_ancestry] end |
#descendant_ids(depth_options = {}) ⇒ Object
181 182 183 |
# File 'lib/ancestry/instance_methods.rb', line 181 def descendant_ids = {} descendants().all(:select => self.base_class.primary_key).collect(&self.base_class.primary_key.to_sym) end |
#descendants(depth_options = {}) ⇒ Object
177 178 179 |
# File 'lib/ancestry/instance_methods.rb', line 177 def descendants = {} self.base_class.ordered_by_ancestry.scope_depth(, depth).scoped :conditions => descendant_conditions end |
#has_children? ⇒ Boolean
143 144 145 |
# File 'lib/ancestry/instance_methods.rb', line 143 def has_children? self.children.exists?({}) end |
#has_siblings? ⇒ Boolean
164 165 166 |
# File 'lib/ancestry/instance_methods.rb', line 164 def has_siblings? self.siblings.count > 1 end |
#is_childless? ⇒ Boolean
147 148 149 |
# File 'lib/ancestry/instance_methods.rb', line 147 def is_childless? !has_children? end |
#is_only_child? ⇒ Boolean
168 169 170 |
# File 'lib/ancestry/instance_methods.rb', line 168 def is_only_child? !has_siblings? end |
#is_root? ⇒ Boolean
126 127 128 |
# File 'lib/ancestry/instance_methods.rb', line 126 def is_root? read_attribute(self.base_class.ancestry_column).blank? end |
#parent ⇒ Object
113 114 115 |
# File 'lib/ancestry/instance_methods.rb', line 113 def parent if parent_id.blank? then nil else self.base_class.find(parent_id) end end |
#parent=(parent) ⇒ Object
Parent
101 102 103 |
# File 'lib/ancestry/instance_methods.rb', line 101 def parent= parent write_attribute(self.base_class.ancestry_column, if parent.blank? then nil else parent.child_ancestry end) end |
#parent_id ⇒ Object
109 110 111 |
# File 'lib/ancestry/instance_methods.rb', line 109 def parent_id if ancestor_ids.empty? then nil else ancestor_ids.last end end |
#parent_id=(parent_id) ⇒ Object
105 106 107 |
# File 'lib/ancestry/instance_methods.rb', line 105 def parent_id= parent_id self.parent = if parent_id.blank? then nil else self.base_class.find(parent_id) end end |
#path(depth_options = {}) ⇒ Object
88 89 90 |
# File 'lib/ancestry/instance_methods.rb', line 88 def path = {} self.base_class.scope_depth(, depth).ordered_by_ancestry.scoped :conditions => path_conditions end |
#path_conditions ⇒ Object
84 85 86 |
# File 'lib/ancestry/instance_methods.rb', line 84 def path_conditions {self.base_class.primary_key => path_ids} end |
#path_ids ⇒ Object
80 81 82 |
# File 'lib/ancestry/instance_methods.rb', line 80 def path_ids ancestor_ids + [id] end |
#root ⇒ Object
122 123 124 |
# File 'lib/ancestry/instance_methods.rb', line 122 def root if root_id == id then self else self.base_class.find(root_id) end end |
#root_id ⇒ Object
Root
118 119 120 |
# File 'lib/ancestry/instance_methods.rb', line 118 def root_id if ancestor_ids.empty? then id else ancestor_ids.first end end |
#sibling_conditions ⇒ Object
Siblings
152 153 154 |
# File 'lib/ancestry/instance_methods.rb', line 152 def sibling_conditions {self.base_class.ancestry_column => read_attribute(self.base_class.ancestry_column)} end |
#sibling_ids ⇒ Object
160 161 162 |
# File 'lib/ancestry/instance_methods.rb', line 160 def sibling_ids siblings.all(:select => self.base_class.primary_key).collect(&self.base_class.primary_key.to_sym) end |
#siblings ⇒ Object
156 157 158 |
# File 'lib/ancestry/instance_methods.rb', line 156 def siblings self.base_class.scoped :conditions => sibling_conditions end |
#subtree(depth_options = {}) ⇒ Object
190 191 192 |
# File 'lib/ancestry/instance_methods.rb', line 190 def subtree = {} self.base_class.ordered_by_ancestry.scope_depth(, depth).scoped :conditions => subtree_conditions end |
#subtree_conditions ⇒ Object
Subtree
186 187 188 |
# File 'lib/ancestry/instance_methods.rb', line 186 def subtree_conditions ["#{self.base_class.primary_key} = ? or #{self.base_class.ancestry_column} like ? or #{self.base_class.ancestry_column} = ?", self.id, "#{child_ancestry}/%", child_ancestry] end |
#subtree_ids(depth_options = {}) ⇒ Object
194 195 196 |
# File 'lib/ancestry/instance_methods.rb', line 194 def subtree_ids = {} subtree().all(:select => self.base_class.primary_key).collect(&self.base_class.primary_key.to_sym) end |
#update_descendants_with_new_ancestry ⇒ Object
Update descendants with new ancestry
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/ancestry/instance_methods.rb', line 9 def update_descendants_with_new_ancestry # Skip this if callbacks are disabled unless ancestry_callbacks_disabled? # If node is valid, not a new record and ancestry was updated ... if changed.include?(self.base_class.ancestry_column.to_s) && !new_record? && valid? # ... for each descendant ... descendants.each do |descendant| # ... replace old ancestry with new ancestry descendant.without_ancestry_callbacks do descendant.update_attribute( self.base_class.ancestry_column, descendant.read_attribute(descendant.class.ancestry_column).gsub( /^#{self.child_ancestry}/, if read_attribute(self.class.ancestry_column).blank? then id.to_s else "#{read_attribute self.class.ancestry_column }/#{id}" end ) ) end end end end end |
#without_ancestry_callbacks ⇒ Object
Callback disabling
199 200 201 202 203 |
# File 'lib/ancestry/instance_methods.rb', line 199 def without_ancestry_callbacks @disable_ancestry_callbacks = true yield @disable_ancestry_callbacks = false end |