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
71 72 73 |
# File 'lib/ancestry/instance_methods.rb', line 71 def ancestor_conditions {self.base_class.primary_key => ancestor_ids} end |
#ancestor_ids ⇒ Object
Ancestors
67 68 69 |
# File 'lib/ancestry/instance_methods.rb', line 67 def ancestor_ids read_attribute(self.base_class.ancestry_column).to_s.split('/').map(&:to_i) end |
#ancestors(depth_options = {}) ⇒ Object
75 76 77 |
# File 'lib/ancestry/instance_methods.rb', line 75 def ancestors = {} self.base_class.scope_depth(, depth).ordered_by_ancestry.scoped :conditions => ancestor_conditions end |
#ancestry_callbacks_disabled? ⇒ Boolean
204 205 206 |
# File 'lib/ancestry/instance_methods.rb', line 204 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 errors[: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
31 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 |
# File 'lib/ancestry/instance_methods.rb', line 31 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
95 96 97 |
# File 'lib/ancestry/instance_methods.rb', line 95 def cache_depth write_attribute self.base_class.depth_cache_column, depth end |
#child_ancestry ⇒ Object
The ancestry value for this record’s children
59 60 61 62 63 64 |
# File 'lib/ancestry/instance_methods.rb', line 59 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
130 131 132 |
# File 'lib/ancestry/instance_methods.rb', line 130 def child_conditions {self.base_class.ancestry_column => child_ancestry} end |
#child_ids ⇒ Object
138 139 140 |
# File 'lib/ancestry/instance_methods.rb', line 138 def child_ids children.all(:select => self.base_class.primary_key).map(&self.base_class.primary_key.to_sym) end |
#children ⇒ Object
134 135 136 |
# File 'lib/ancestry/instance_methods.rb', line 134 def children self.base_class.scoped :conditions => child_conditions end |
#depth ⇒ Object
91 92 93 |
# File 'lib/ancestry/instance_methods.rb', line 91 def depth ancestor_ids.size end |
#descendant_conditions ⇒ Object
Descendants
172 173 174 |
# File 'lib/ancestry/instance_methods.rb', line 172 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
180 181 182 |
# File 'lib/ancestry/instance_methods.rb', line 180 def descendant_ids = {} descendants().all(:select => self.base_class.primary_key).collect(&self.base_class.primary_key.to_sym) end |
#descendants(depth_options = {}) ⇒ Object
176 177 178 |
# File 'lib/ancestry/instance_methods.rb', line 176 def descendants = {} self.base_class.ordered_by_ancestry.scope_depth(, depth).scoped :conditions => descendant_conditions end |
#has_children? ⇒ Boolean
142 143 144 |
# File 'lib/ancestry/instance_methods.rb', line 142 def has_children? self.children.exists? {} end |
#has_siblings? ⇒ Boolean
163 164 165 |
# File 'lib/ancestry/instance_methods.rb', line 163 def has_siblings? self.siblings.count > 1 end |
#is_childless? ⇒ Boolean
146 147 148 |
# File 'lib/ancestry/instance_methods.rb', line 146 def is_childless? !has_children? end |
#is_only_child? ⇒ Boolean
167 168 169 |
# File 'lib/ancestry/instance_methods.rb', line 167 def is_only_child? !has_siblings? end |
#is_root? ⇒ Boolean
125 126 127 |
# File 'lib/ancestry/instance_methods.rb', line 125 def is_root? read_attribute(self.base_class.ancestry_column).blank? end |
#parent ⇒ Object
112 113 114 |
# File 'lib/ancestry/instance_methods.rb', line 112 def parent if parent_id.blank? then nil else self.base_class.find(parent_id) end end |
#parent=(parent) ⇒ Object
Parent
100 101 102 |
# File 'lib/ancestry/instance_methods.rb', line 100 def parent= parent write_attribute(self.base_class.ancestry_column, if parent.blank? then nil else parent.child_ancestry end) end |
#parent_id ⇒ Object
108 109 110 |
# File 'lib/ancestry/instance_methods.rb', line 108 def parent_id if ancestor_ids.empty? then nil else ancestor_ids.last end end |
#parent_id=(parent_id) ⇒ Object
104 105 106 |
# File 'lib/ancestry/instance_methods.rb', line 104 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
87 88 89 |
# File 'lib/ancestry/instance_methods.rb', line 87 def path = {} self.base_class.scope_depth(, depth).ordered_by_ancestry.scoped :conditions => path_conditions end |
#path_conditions ⇒ Object
83 84 85 |
# File 'lib/ancestry/instance_methods.rb', line 83 def path_conditions {self.base_class.primary_key => path_ids} end |
#path_ids ⇒ Object
79 80 81 |
# File 'lib/ancestry/instance_methods.rb', line 79 def path_ids ancestor_ids + [id] end |
#root ⇒ Object
121 122 123 |
# File 'lib/ancestry/instance_methods.rb', line 121 def root if root_id == id then self else self.base_class.find(root_id) end end |
#root_id ⇒ Object
Root
117 118 119 |
# File 'lib/ancestry/instance_methods.rb', line 117 def root_id if ancestor_ids.empty? then id else ancestor_ids.first end end |
#sibling_conditions ⇒ Object
Siblings
151 152 153 |
# File 'lib/ancestry/instance_methods.rb', line 151 def sibling_conditions {self.base_class.ancestry_column => read_attribute(self.base_class.ancestry_column)} end |
#sibling_ids ⇒ Object
159 160 161 |
# File 'lib/ancestry/instance_methods.rb', line 159 def sibling_ids siblings.all(:select => self.base_class.primary_key).collect(&self.base_class.primary_key.to_sym) end |
#siblings ⇒ Object
155 156 157 |
# File 'lib/ancestry/instance_methods.rb', line 155 def siblings self.base_class.scoped :conditions => sibling_conditions end |
#subtree(depth_options = {}) ⇒ Object
189 190 191 |
# File 'lib/ancestry/instance_methods.rb', line 189 def subtree = {} self.base_class.ordered_by_ancestry.scope_depth(, depth).scoped :conditions => subtree_conditions end |
#subtree_conditions ⇒ Object
Subtree
185 186 187 |
# File 'lib/ancestry/instance_methods.rb', line 185 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
193 194 195 |
# File 'lib/ancestry/instance_methods.rb', line 193 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 |
# 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.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.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
198 199 200 201 202 |
# File 'lib/ancestry/instance_methods.rb', line 198 def without_ancestry_callbacks @disable_ancestry_callbacks = true yield @disable_ancestry_callbacks = false end |