Module: Mongoid::Ancestry
- Extended by:
- ActiveSupport::Concern
- Includes:
- Mongoid::Attributes::Dynamic
- Defined in:
- lib/mongoid-ancestry.rb,
lib/mongoid-ancestry/version.rb,
lib/mongoid-ancestry/exceptions.rb,
lib/mongoid-ancestry/class_methods.rb,
lib/mongoid-ancestry/instance_methods.rb
Defined Under Namespace
Modules: ClassMethods
Classes: Error, IntegrityError
Constant Summary
collapse
- VERSION =
'0.4.2'
Instance Method Summary
collapse
Instance Method Details
#ancestor_conditions ⇒ Object
86
87
88
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 86
def ancestor_conditions
{ :_id.in => ancestor_ids }
end
|
#ancestor_ids ⇒ Object
82
83
84
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 82
def ancestor_ids
read_attribute(self.base_class.ancestry_field).to_s.split('/').map { |id| cast_primary_key(id) }
end
|
#ancestors(depth_options = {}) ⇒ Object
90
91
92
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 90
def ancestors depth_options = {}
self.base_class.scope_depth(depth_options, depth).where(ancestor_conditions)
end
|
#ancestry_callbacks_disabled? ⇒ Boolean
227
228
229
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 227
def ancestry_callbacks_disabled?
!!@disable_ancestry_callbacks
end
|
#ancestry_exclude_self ⇒ Object
Validate that the ancestors don’t include itself
5
6
7
8
9
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 5
def ancestry_exclude_self
if ancestor_ids.include? id
errors.add(:base, "#{self.class.name.humanize} cannot be a descendant of itself.")
end
end
|
#apply_orphan_strategy ⇒ Object
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 40
def apply_orphan_strategy
unless ancestry_callbacks_disabled?
unless new_record?
if self.base_class.orphan_strategy == :rootify
descendants.each do |descendant|
descendant.without_ancestry_callbacks do
val = \
unless descendant.ancestry == child_ancestry
descendant.read_attribute(descendant.class.ancestry_field).gsub(/^#{child_ancestry}\//, '')
end
descendant.update_attribute descendant.class.ancestry_field, val
end
end
elsif self.base_class.orphan_strategy == :destroy
descendants.all.each do |descendant|
descendant.without_ancestry_callbacks { descendant.destroy }
end
elsif self.base_class.orphan_strategy == :restrict
raise Error.new('Cannot delete record because it has descendants.') unless is_childless?
end
end
end
end
|
#cache_depth ⇒ Object
110
111
112
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 110
def cache_depth
write_attribute self.base_class.depth_cache_field, depth
end
|
#child_ancestry ⇒ Object
The ancestry value for this record’s children
70
71
72
73
74
75
76
77
78
79
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 70
def child_ancestry
raise Error.new('No child ancestry for new record. Save record before performing tree operations.') if new_record?
if self.send("#{self.base_class.ancestry_field}_was").blank?
id.to_s
else
"#{self.send "#{self.base_class.ancestry_field}_was"}/#{id}"
end
end
|
#child_conditions ⇒ Object
146
147
148
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 146
def child_conditions
{self.base_class.ancestry_field => child_ancestry}
end
|
#child_ids ⇒ Object
154
155
156
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 154
def child_ids
children.only(:_id).map(&:id)
end
|
#children ⇒ Object
150
151
152
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 150
def children
self.base_class.where(child_conditions)
end
|
#depth ⇒ Object
106
107
108
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 106
def depth
ancestor_ids.size
end
|
#descendant_conditions ⇒ Object
188
189
190
191
192
193
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 188
def descendant_conditions
[
{ self.base_class.ancestry_field => /^#{child_ancestry}\// },
{ self.base_class.ancestry_field => child_ancestry }
]
end
|
#descendant_ids(depth_options = {}) ⇒ Object
199
200
201
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 199
def descendant_ids depth_options = {}
descendants(depth_options).only(:_id).map(&:id)
end
|
#descendants(depth_options = {}) ⇒ Object
195
196
197
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 195
def descendants depth_options = {}
self.base_class.scope_depth(depth_options, depth).any_of(descendant_conditions)
end
|
#has_children? ⇒ Boolean
158
159
160
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 158
def has_children?
self.children.present?
end
|
#has_siblings? ⇒ Boolean
179
180
181
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 179
def has_siblings?
self.siblings.count > 1
end
|
#is_childless? ⇒ Boolean
162
163
164
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 162
def is_childless?
!has_children?
end
|
#is_only_child? ⇒ Boolean
183
184
185
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 183
def is_only_child?
!has_siblings?
end
|
#is_root? ⇒ Boolean
141
142
143
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 141
def is_root?
read_attribute(self.base_class.ancestry_field).blank?
end
|
#parent ⇒ Object
128
129
130
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 128
def parent
parent_id.blank? ? nil : self.base_class.find(parent_id)
end
|
#parent=(parent) ⇒ Object
115
116
117
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 115
def parent= parent
write_attribute(self.base_class.ancestry_field, parent.blank? ? nil : parent.child_ancestry)
end
|
#parent_id ⇒ Object
123
124
125
126
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 123
def parent_id
parent_id = read_attribute(self.base_class.ancestry_field).to_s.split('/').last
return cast_primary_key(parent_id) if parent_id
end
|
#parent_id=(parent_id) ⇒ Object
119
120
121
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 119
def parent_id= parent_id
self.parent = parent_id.blank? ? nil : self.base_class.find(parent_id)
end
|
#path(depth_options = {}) ⇒ Object
102
103
104
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 102
def path depth_options = {}
self.base_class.scope_depth(depth_options, depth).where(path_conditions)
end
|
#path_conditions ⇒ Object
98
99
100
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 98
def path_conditions
{ :_id.in => path_ids }
end
|
#path_ids ⇒ Object
94
95
96
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 94
def path_ids
ancestor_ids + [id]
end
|
#root ⇒ Object
137
138
139
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 137
def root
(root_id == id) ? self : self.base_class.find(root_id)
end
|
#root_id ⇒ Object
133
134
135
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 133
def root_id
ancestor_ids.empty? ? id : ancestor_ids.first
end
|
#sibling_conditions ⇒ Object
167
168
169
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 167
def sibling_conditions
{self.base_class.ancestry_field => read_attribute(self.base_class.ancestry_field)}
end
|
#sibling_ids ⇒ Object
175
176
177
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 175
def sibling_ids
siblings.only(:_id).map(&:id)
end
|
#siblings ⇒ Object
171
172
173
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 171
def siblings
self.base_class.where sibling_conditions
end
|
#subtree(depth_options = {}) ⇒ Object
212
213
214
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 212
def subtree depth_options = {}
self.base_class.scope_depth(depth_options, depth).any_of(subtree_conditions)
end
|
#subtree_conditions ⇒ Object
204
205
206
207
208
209
210
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 204
def subtree_conditions
[
{ :_id => id },
{ self.base_class.ancestry_field => /^#{child_ancestry}\// },
{ self.base_class.ancestry_field => child_ancestry }
]
end
|
#subtree_ids(depth_options = {}) ⇒ Object
216
217
218
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 216
def subtree_ids depth_options = {}
subtree(depth_options).only(:_id).map(&:id)
end
|
#touch_parent ⇒ Object
35
36
37
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 35
def touch_parent
parent.touch
end
|
#update_descendants_with_new_ancestry ⇒ Object
Update descendants with new ancestry
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 12
def update_descendants_with_new_ancestry
unless ancestry_callbacks_disabled?
if changed.include?(self.base_class.ancestry_field.to_s) && !new_record? && valid?
descendants.each do |descendant|
descendant.without_ancestry_callbacks do
for_replace = \
if read_attribute(self.class.ancestry_field).blank?
id.to_s
else
"#{read_attribute self.class.ancestry_field}/#{id}"
end
new_ancestry = descendant.read_attribute(descendant.class.ancestry_field).gsub(/^#{self.child_ancestry}/, for_replace)
descendant.update_attribute(self.base_class.ancestry_field, new_ancestry)
end
end
end
end
end
|
#without_ancestry_callbacks ⇒ Object
221
222
223
224
225
|
# File 'lib/mongoid-ancestry/instance_methods.rb', line 221
def without_ancestry_callbacks
@disable_ancestry_callbacks = true
yield
@disable_ancestry_callbacks = false
end
|