ancestry 1.2.4 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +6 -3
- data/ancestry.gemspec +1 -1
- data/lib/ancestry/class_methods.rb +30 -27
- metadata +5 -12
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Ancestry
|
2
2
|
|
3
|
-
Ancestry is a gem/plugin that allows the records of a Ruby on Rails ActiveRecord model to be organised as a tree structure (or hierarchy). It uses a single, intuitively formatted database column, using a variation on the materialised path pattern. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single
|
3
|
+
Ancestry is a gem/plugin that allows the records of a Ruby on Rails ActiveRecord model to be organised as a tree structure (or hierarchy). It uses a single, intuitively formatted database column, using a variation on the materialised path pattern. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single SQL query. Additional features are STI support, scopes, depth caching, depth constraints, easy migration from older plugins/gems, integrity checking, integrity restoration, arrangement of (sub)tree into hashes and different strategies for dealing with orphaned records.
|
4
4
|
|
5
5
|
= Installation
|
6
6
|
|
@@ -228,7 +228,7 @@ The Ancestry gem comes with a unit test suite consisting of about 1800 assertion
|
|
228
228
|
|
229
229
|
= Internals
|
230
230
|
|
231
|
-
As can be seen in the previous section, Ancestry stores a path from the root to the parent for every node. This is a variation on the materialised path database pattern. It allows Ancestry to fetch any relation (siblings, descendants, etc.) in a single
|
231
|
+
As can be seen in the previous section, Ancestry stores a path from the root to the parent for every node. This is a variation on the materialised path database pattern. It allows Ancestry to fetch any relation (siblings, descendants, etc.) in a single SQL query without the complicated algorithms and incomprehensibility associated with left and right values. Additionally, any inserts, deletes and updates only affect nodes within the affected node's own subtree.
|
232
232
|
|
233
233
|
In the example above, the ancestry column is created as a string. This puts a limitation on the depth of the tree of about 40 or 50 levels, which I think may be enough for most users. To increase the maximum depth of the tree, increase the size of the string that is being used or change it to a text to remove the limitation entirely. Changing it to a text will however decrease performance because an index cannot be put on the column in that case.
|
234
234
|
|
@@ -238,7 +238,10 @@ The materialised path pattern requires Ancestry to use a 'like' condition in ord
|
|
238
238
|
|
239
239
|
The latest version of ancestry is recommended. The three numbers of each version numbers are respectively the major, minor and patch versions. We started with major version 1 because it looks so much better and ancestry was already quite mature and complete when it was published. The major version is only bumped when backwards compatibility is broken. The minor version is bumped when new features are added. The patch version is bumped when bugs are fixed.
|
240
240
|
|
241
|
-
- Version 1.2.
|
241
|
+
- Version 1.2.5 (2012-03-15)
|
242
|
+
- Fixed warnings: "parenthesize argument(s) for future version"
|
243
|
+
- Fixed a bug in the restore_ancestry_integrity! method (thx Arthur Holstvoogd)
|
244
|
+
- Version 1.2.4 (2011-04-22)
|
242
245
|
- Prepended table names to column names in queries (thx raelik)
|
243
246
|
- Better check to see if acts_as_tree can be overloaded (thx jims)
|
244
247
|
- Performance inprovements (thx kueda)
|
data/ancestry.gemspec
CHANGED
@@ -3,7 +3,7 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.description = 'Organise ActiveRecord model into a tree structure'
|
4
4
|
s.summary = 'Ancestry allows the records of a ActiveRecord model to be organised in a tree structure, using a single, intuitively formatted database column. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single sql query. Additional features are named_scopes, integrity checking, integrity restoration, arrangement of (sub)tree into hashes and different strategies for dealing with orphaned records.'
|
5
5
|
|
6
|
-
s.version = '1.2.
|
6
|
+
s.version = '1.2.5'
|
7
7
|
|
8
8
|
s.author = 'Stefan Kroes'
|
9
9
|
s.email = 's.a.kroes@gmail.com'
|
@@ -78,19 +78,19 @@ module Ancestry
|
|
78
78
|
begin
|
79
79
|
# ... check validity of ancestry column
|
80
80
|
if !node.valid? and !node.errors[node.class.ancestry_column].blank?
|
81
|
-
raise Ancestry::AncestryIntegrityException.new
|
81
|
+
raise Ancestry::AncestryIntegrityException.new("Invalid format for ancestry column of node #{node.id}: #{node.read_attribute node.ancestry_column}.")
|
82
82
|
end
|
83
83
|
# ... check that all ancestors exist
|
84
84
|
node.ancestor_ids.each do |ancestor_id|
|
85
85
|
unless exists? ancestor_id
|
86
|
-
raise Ancestry::AncestryIntegrityException.new
|
86
|
+
raise Ancestry::AncestryIntegrityException.new("Reference to non-existent node in node #{node.id}: #{ancestor_id}.")
|
87
87
|
end
|
88
88
|
end
|
89
89
|
# ... check that all node parents are consistent with values observed earlier
|
90
90
|
node.path_ids.zip([nil] + node.path_ids).each do |node_id, parent_id|
|
91
91
|
parents[node_id] = parent_id unless parents.has_key? node_id
|
92
92
|
unless parents[node_id] == parent_id
|
93
|
-
raise Ancestry::AncestryIntegrityException.new
|
93
|
+
raise Ancestry::AncestryIntegrityException.new("Conflicting parent id found in node #{node.id}: #{parent_id || 'nil'} for node #{node_id} while expecting #{parents[node_id] || 'nil'}")
|
94
94
|
end
|
95
95
|
end
|
96
96
|
rescue Ancestry::AncestryIntegrityException => integrity_exception
|
@@ -107,33 +107,36 @@ module Ancestry
|
|
107
107
|
# Integrity restoration
|
108
108
|
def restore_ancestry_integrity!
|
109
109
|
parents = {}
|
110
|
-
#
|
111
|
-
self.base_class.
|
112
|
-
#
|
113
|
-
|
114
|
-
|
115
|
-
|
110
|
+
# Wrap the whole thing in a transaction ...
|
111
|
+
self.base_class.transaction do
|
112
|
+
# For each node ...
|
113
|
+
self.base_class.find_each do |node|
|
114
|
+
# ... set its ancestry to nil if invalid
|
115
|
+
if !node.valid? and !node.errors[node.class.ancestry_column].blank?
|
116
|
+
node.without_ancestry_callbacks do
|
117
|
+
node.update_attribute node.ancestry_column, nil
|
118
|
+
end
|
116
119
|
end
|
117
|
-
|
118
|
-
|
119
|
-
parents[node.id] = node.parent_id if exists? node.parent_id
|
120
|
+
# ... save parent of this node in parents array if it exists
|
121
|
+
parents[node.id] = node.parent_id if exists? node.parent_id
|
120
122
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
end
|
128
|
-
# For each node ...
|
129
|
-
self.base_class.find_each do |node|
|
130
|
-
# ... rebuild ancestry from parents array
|
131
|
-
ancestry, parent = nil, parents[node.id]
|
132
|
-
until parent.nil?
|
133
|
-
ancestry, parent = if ancestry.nil? then parent else "#{parent}/#{ancestry}" end, parents[parent]
|
123
|
+
# Reset parent id in array to nil if it introduces a cycle
|
124
|
+
parent = parents[node.id]
|
125
|
+
until parent.nil? || parent == node.id
|
126
|
+
parent = parents[parent]
|
127
|
+
end
|
128
|
+
parents[node.id] = nil if parent == node.id
|
134
129
|
end
|
135
|
-
node
|
136
|
-
|
130
|
+
# For each node ...
|
131
|
+
self.base_class.find_each do |node|
|
132
|
+
# ... rebuild ancestry from parents array
|
133
|
+
ancestry, parent = nil, parents[node.id]
|
134
|
+
until parent.nil?
|
135
|
+
ancestry, parent = if ancestry.nil? then parent else "#{parent}/#{ancestry}" end, parents[parent]
|
136
|
+
end
|
137
|
+
node.without_ancestry_callbacks do
|
138
|
+
node.update_attribute node.ancestry_column, ancestry
|
139
|
+
end
|
137
140
|
end
|
138
141
|
end
|
139
142
|
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ancestry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
4
|
+
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 1
|
8
7
|
- 2
|
9
|
-
-
|
10
|
-
version: 1.2.
|
8
|
+
- 5
|
9
|
+
version: 1.2.5
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Stefan Kroes
|
@@ -15,18 +14,16 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date:
|
17
|
+
date: 2012-03-15 00:00:00 +01:00
|
19
18
|
default_executable:
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: activerecord
|
23
22
|
prerelease: false
|
24
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
24
|
requirements:
|
27
25
|
- - ">="
|
28
26
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 3
|
30
27
|
segments:
|
31
28
|
- 2
|
32
29
|
- 2
|
@@ -63,27 +60,23 @@ rdoc_options: []
|
|
63
60
|
require_paths:
|
64
61
|
- lib
|
65
62
|
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
63
|
requirements:
|
68
64
|
- - ">="
|
69
65
|
- !ruby/object:Gem::Version
|
70
|
-
hash: 3
|
71
66
|
segments:
|
72
67
|
- 0
|
73
68
|
version: "0"
|
74
69
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
-
none: false
|
76
70
|
requirements:
|
77
71
|
- - ">="
|
78
72
|
- !ruby/object:Gem::Version
|
79
|
-
hash: 3
|
80
73
|
segments:
|
81
74
|
- 0
|
82
75
|
version: "0"
|
83
76
|
requirements: []
|
84
77
|
|
85
78
|
rubyforge_project:
|
86
|
-
rubygems_version: 1.
|
79
|
+
rubygems_version: 1.3.6
|
87
80
|
signing_key:
|
88
81
|
specification_version: 3
|
89
82
|
summary: Ancestry allows the records of a ActiveRecord model to be organised in a tree structure, using a single, intuitively formatted database column. It exposes all the standard tree structure relations (ancestors, parent, root, children, siblings, descendants) and all of them can be fetched in a single sql query. Additional features are named_scopes, integrity checking, integrity restoration, arrangement of (sub)tree into hashes and different strategies for dealing with orphaned records.
|