Module: SimplyCouch::Model::Ancestry::InstanceMethods

Defined in:
lib/simply_couch/model/ancestry.rb

Instance Method Summary collapse

Instance Method Details

#add_child(child) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/simply_couch/model/ancestry.rb', line 54

def add_child(child)
  unless children.include?(child)
    @children ||= []
    @children += [child]
    child.parent = self

    # update by_property of child if it differs from parent
    if root_property = self.class.ancestry_by_property
      child.send("#{root_property}=", send(root_property)) if send(root_property) != child.send(root_property)
    end
    @descendants = nil # reload descendants if requested
  end
  child
end

#ancestorsObject



149
150
151
152
153
# File 'lib/simply_couch/model/ancestry.rb', line 149

def ancestors
  return [] unless parent_ids.any?
  return [parent] if parent_ids.size == 1 # optimization, parent is pre-loaded many times
  (self.class.database.couchrest_database.bulk_load(parent_ids)['rows'] || []).map{|h| h['doc']}.compact
end

#childrenObject



5
6
7
8
9
10
11
12
13
# File 'lib/simply_couch/model/ancestry.rb', line 5

def children
  return @children if @children
  if root_property = self.class.ancestry_by_property
    @children = self.class.database.view(self.class.children_view(startkey: [send(root_property), id], endkey: [send(root_property), id, {}], reduce: false))
  else
    @children = self.class.database.view(self.class.children_view(startkey: [id], endkey: [id, {}], reduce: false))
  end
  @children
end

#children=(val) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/simply_couch/model/ancestry.rb', line 14

def children=(val)
  @old_descendants = descendants
  @children = val
  @children.map(&:subtree) # preload children hierarchy
  @new_descendants = []
  for child in @children
    for descendant in child.descendants
      @new_descendants << descendant
    end
  end
  @old_descendants.each{|d| d.instance_variable_set('@parent', nil); d.path_ids = [d.id]} # old descendants become root
  (@old_descendants - @new_descendants).map(&:save) # Persist old descendants not present in new descendants

  # update by_property of children if it differs from parent (locale or ... orther field is required to have the same values)
  if root_property = self.class.ancestry_by_property
    self_by_property = send(root_property)
    for child in @children | @new_descendants
      child.send("#{root_property}=", self_by_property) if self_by_property != child.send(root_property)
    end
  end

  self.class.set_parent(self, @children) # recurring update of parent in subtree of children
  @descendants = (@children | @new_descendants)
  clear_cached_ancestors

  # Return wether all children can be saved :)
  (@descendants).map(&:save).all?
end

#clear_cached_ancestorsObject

reset cache attributes for ancestors



44
45
46
47
48
49
50
51
52
# File 'lib/simply_couch/model/ancestry.rb', line 44

def clear_cached_ancestors
  ansi = self
  while ancestor = ansi.instance_variable_get('@parent').presence
    ancestor.instance_variable_set('@descendants', nil)
    ancestor.instance_variable_set('@children', nil)
    ansi = ancestor
  end
  self
end

#create_tree_pathObject

Triggered after create, because needs id



99
100
101
102
103
104
105
# File 'lib/simply_couch/model/ancestry.rb', line 99

def create_tree_path
  return false unless id
  newpath = ( (parent && parent.path_ids) || []) + [id]
  return true if path_ids == newpath
  self.path_ids = newpath
  save
end

#descendantsObject

Get all descendants



70
71
72
73
74
75
76
77
78
79
80
# File 'lib/simply_couch/model/ancestry.rb', line 70

def descendants
  return @descendants if @descendants
  return @descendants = [] if id.blank?
  if root_property = self.class.ancestry_by_property
    @descendants = self.class.database.view(self.class.subtree_view(startkey: [send(root_property), id], endkey: [send(root_property), id, {}], reduce: false)).sort_by!{|d| [d.path_ids.size, d.position]}
  else
    @descendants = self.class.database.view(self.class.subtree_view(startkey: [id], endkey: [id, {}], reduce: false)).sort_by{|d| [d.path_ids.size, d.position]}
  end
  @children = self.class.build_tree(@descendants)
  @descendants
end

#parentObject



107
108
109
110
111
# File 'lib/simply_couch/model/ancestry.rb', line 107

def parent
  return @parent if @parent
  return @parent = self.class.find(parent_id) if parent_id.present?
  nil
end

#parent=(val) ⇒ Object



113
114
115
116
117
118
119
120
121
# File 'lib/simply_couch/model/ancestry.rb', line 113

def parent=(val)
  if @parent != val
    @parent = val
    update_tree_path
    @parent.children += [self] unless @parent.children.include?(self)
    save
  end
  val
end

#parent_idObject



141
142
143
# File 'lib/simply_couch/model/ancestry.rb', line 141

def parent_id
  @parent_id ||= parent_ids.last
end

#parent_id=(val) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/simply_couch/model/ancestry.rb', line 123

def parent_id=(val)
  if parent_id != val.presence
    @parent = nil
    @parent_id = val.presence
    subtree if persisted?
    path_ids_will_change!
    if @parent_id
      @parent = parent
      self.path_ids = parent.path_ids + [id]
      self.class.set_parent(self, @children) if persisted?
    else
      self.path_ids = [id]
      self.class.set_parent(self, @children) if persisted?
    end
    @descendants.map(&:save) if persisted? && save
  end
end

#parent_idsObject



145
146
147
# File 'lib/simply_couch/model/ancestry.rb', line 145

def parent_ids
  (path_ids || [])[0..-2]
end

#parentsObject



154
155
156
# File 'lib/simply_couch/model/ancestry.rb', line 154

def parents
  ancestors
end

#subtreeObject

Find subtree of a given page and set children with the result (important to get same children object ids as in descendants)



83
84
85
# File 'lib/simply_couch/model/ancestry.rb', line 83

def subtree
  @children = self.class.build_tree(descendants)
end

#tree_depthObject



162
163
164
# File 'lib/simply_couch/model/ancestry.rb', line 162

def tree_depth
  (path_ids || [nil]).size - 1
end

#tree_pathObject



158
159
160
# File 'lib/simply_couch/model/ancestry.rb', line 158

def tree_path
  ancestors + [self]
end

#update_tree_pathObject

Triggered before save



88
89
90
91
92
93
94
95
96
# File 'lib/simply_couch/model/ancestry.rb', line 88

def update_tree_path
  return false unless id
  newpath = ( (parent && parent.path_ids) || []) + [id]
  if path_ids != newpath
    path_ids_will_change!
    self.path_ids = newpath
  end
  self
end