ancestry 3.0.6 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aec53fbb23531d1bf8431468c6a8b60746487f22fa16701d07b7874451ed0b7f
4
- data.tar.gz: 8ce0b89ebb790f0e54ea4edaa9dec4581d4aefbdc211243b1e123132e62a4a4f
3
+ metadata.gz: d7d01ac0d4c8faa7ad66a0a8e5454625d723fc9226a7e0eb84b358fd25003148
4
+ data.tar.gz: e27cf882086e2c674972251bf35a52eca003d601dcf5d9ba390c1785f8900033
5
5
  SHA512:
6
- metadata.gz: 40a01583120fc47577cf59064d7d4dce4a2788607d09f3205908a2875252e58874aa1c82d1fae7bbefd86548bfd9cc0bfd029aac51d358cdfaceb9b2f8f1ba74
7
- data.tar.gz: f921a574313fe737d13630e50afb2cea865834b59e72ca32c256a58289b371bb5cffadf887177a595a0a69f0721bd7984e9347ac5081069f8f6586433fff94aa
6
+ metadata.gz: b2b1a7a69fa27d6f40f1c39a700c5926d3fa1b5da4637800b87d1ad274458cb0ca39a497d505f2b6224031914a484349cef8c433b191ba131e1396431fce767d
7
+ data.tar.gz: 9fd95019be895afcc8eeee14be8a7776a90a29ded86d25a3cb82a92097cfa7a141f8a765a062e4ac6f5665e6bf7656d8e9fbde030329b713f286f9d96fa179b7
data/CHANGELOG.md ADDED
@@ -0,0 +1,286 @@
1
+ # Ancestry Changelog
2
+
3
+ Doing our best at supporting [SemVer](http://semver.org/) with
4
+ a nice looking [Changelog](http://keepachangelog.com).
5
+
6
+ ## Version [HEAD] <sub><sup>now</sub></sup>
7
+
8
+ ## Version [4.0.0] <sub><sup>2021-04-12</sub></sup>
9
+
10
+ * dropped support for rails 4.2 and 5.0 (thx @d-m-u)
11
+ * better documentation counter cache option (thx @pustomytnyk)
12
+ * clean up code (thx @amatsuda @d-m-u)
13
+ * fixed rails 6.1 support (thx @cmr119 @d-staehler @danini-the-panini )
14
+ * phasing out `parent_id?`, `ancestors?` and using `has_parent?` instead
15
+ * fixed postgres order bug on rails 6.2 and higher (thx @smoyt)
16
+
17
+ ## Version [3.2.1] <sub><sup>2020-09-23</sub></sup>
18
+
19
+ * fixed gemspec to include locales and pg (thx @HectorMF)
20
+
21
+ ## Version [3.2.0] <sub><sup>2020-09-23</sub></sup>
22
+
23
+ * introduce i18n
24
+ * pg sql optimization for ancestry changes (thx @suonlight and @geis)
25
+ * pg sql optimization for sorting (thx @brendon and @d-m-u)
26
+ * fix to humanise model name (thx @mkllnk)
27
+ * able to convert to ancestry from a parent_id column with a different name
28
+ * documentation fixes for better diagrams and grammar (thx @dtamais, @d-m-u, and @CamilleDrapier)
29
+
30
+ ## Version [3.1.0] <sub><sup>2020-08-03</sub></sup>
31
+
32
+ * `:primary_key_format` method lets you change syntax. good for uuids.
33
+ * changed code from being `ancestry` string to `ancestry_ids` focused. May break monkey patches.
34
+ * Moved many methods from `has_ancestry` and `InstanceMethods` to `MaterializedPath`. May break monkey patches.
35
+ * Removed tests for `mysql` driver. Starting with rails 4.1, it supports `mysql2` driver.
36
+ * Better documentation for relationships (thnx @dtamai and @d-m-u)
37
+ * Fix creating children in `after_*` callbacks (thx @jstirk)
38
+
39
+ ## Version [3.0.7] <sub><sup>2018-11-06</sub></sup>
40
+
41
+ * Fixed rails 5.1 change detection (thx @jrafanie)
42
+ * Introduce counter cache (thx @hw676018683)
43
+
44
+ ## Version [3.0.6] <sub><sup>2018-11-06</sub></sup>
45
+
46
+ * Fixed rails 4.1 version check (thx @myxoh)
47
+
48
+ ## Version [3.0.5] <sub><sup>2018-11-06</sub></sup>
49
+
50
+ ## Changed
51
+
52
+ * Added indirect children support (thx @tilo)
53
+ * Fixed test sorting for pg on mac osx
54
+
55
+ ## Fixes
56
+
57
+ * Reduced memory footprint of parsing ancestry column (thx @NickLaMuro)
58
+
59
+ ## Version [3.0.4] <sub><sup>2018-10-27</sub></sup>
60
+
61
+ ## Fixes
62
+
63
+ * Properly detects non-integer columns (thx @adam101)
64
+ * Arrange no longer drops nodes due to missing parents (thx @trafium)
65
+
66
+ ## Version [3.0.3] <sub><sup>2018-10-23</sub></sup>
67
+
68
+ This branch (3.x) should still be compatible with rails 3 and 4.
69
+ Rails 5.1 and 5.2 support were introduced in this version, but ongoing support
70
+ has been moved to ancestry 4.0
71
+
72
+ ## Fixes
73
+
74
+ * Reduce object allocation (thx @NickLaMuro)
75
+ * Rails 5.1 fixes (thx @ctrombley)
76
+ * Avoid redundant query to DB in subtree_of scope (thx @Slike9)
77
+ * Syntax tweaks (thx @ekohl, @richardonrails)
78
+ * Fixed reverse ordering
79
+ * Dropped builds for ruby 1.9.3, 2.0, 2.1, and 2.2
80
+ * Dropped builds for Rails 3.x and 4.x (will use Active Record `or` syntax)
81
+
82
+ ## Version [3.0.2] <sub><sup>2018-04-24</sub></sup>
83
+
84
+ ## Fixes
85
+
86
+ * fixed `order_by_ancestry` bug
87
+ * fixed order tests for postgres on mac (it uses a different collation)
88
+ * fixed documentation (thx @besquared, @danfrenette, @eiwi1101, @isimluk, @mabusaad, @tilsammans)
89
+ * added missing `Ancestry::version`
90
+ * added Rails 5.2 support (thx @jjuliano)
91
+
92
+ ## Version [3.0.1] <sub><sup>2017-07-05</sub></sup>
93
+
94
+ ## Fixes
95
+
96
+ * added gem metadata
97
+ * fixed keep a changelog link (thx @mattbrictson)
98
+ * added alias has_parent?
99
+ * fixed bug where unscoping too much (thx @brendon)
100
+ * fixed tests on mysql 5.7 and rails 3.2
101
+ * Dropped 3.1 scope changes
102
+
103
+ ## Version [3.0.0] <sub><sup>2017-05-18</sub></sup>
104
+
105
+ ## Changed
106
+
107
+ * Dropping Rails 3.0, and 3.1. Added Rails 5.1 support (thx @ledermann)
108
+ * Dropping Rails 4.0, 4.1 for build reasons. Since 4.2 is supported, all 4.x should still work.
109
+
110
+ ## Fixes
111
+
112
+ * Performance: Use `pluck` vs `map` for ids (thx @njakobsen and @culturecode)
113
+ * Fixed acts_as_tree compatibility (thx @crazymykl)
114
+ * Fixed loading ActiveRails prematurely (thx @vovimayhem)
115
+ * Fixes exist (thx @ledermann)
116
+ * Properly touches parents when different class for STI (thx @samtgarson)
117
+ * Fixed issues with parent_id (only present on master) (thx @domcleal)
118
+
119
+ ## Version [2.2.2] <sub><sup>2016-11-01</sub></sup>
120
+
121
+ ### Changed
122
+
123
+ * Use `COALESCE` only for sorting versions greater than 5.0
124
+ * Fixed bug with explicit order clauses (introduced in 2.2.0)
125
+ * No longer load schema on `has_ancestry` load (thx @ledermann)
126
+
127
+ ## Version [2.2.1] <sub><sup>2016-10-25</sub></sup>
128
+
129
+ Sorry for blip, local master got out of sync with upstream master.
130
+ Missed 2 commits (which are feature adds)
131
+
132
+ ### Added
133
+ * Use like (vs ilike) for rails 5.0 (performance enhancement)
134
+ * Use `COALESCE` for sorting on pg, mysql, and sqlite vs `CASE`
135
+
136
+ ## Version [2.2.0] <sub><sup>2016-10-25</sub></sup>
137
+
138
+ ### Added
139
+ * Predicates for scopes: e.g.: `ancestor_of?`, `parent_of?` (thx @neglectedvalue)
140
+ * Scope `path_of`
141
+
142
+ ### Changed
143
+ * `arrange` now accepts blocks (thx @mastfish)
144
+ * Performance tuning `arrange_node` (thx @fryguy)
145
+ * In orphan strategy, set `ancestry` to `nil` for no parents (thx @haslinger)
146
+ * Only updates `updated_at` when a record is changed (thx @brocktimus)
147
+ * No longer casts text primary key as an integer
148
+ * Upgrading tests for ruby versions (thx @brocktimus, @fryguy, @yui-knk)
149
+ * Fix non-default ancestry not getting used properly (thx @javiyu)
150
+
151
+ ## Version [2.1.0] <sub><sup>2014-04-16</sub></sup>
152
+ * Added arrange_serializable (thx @krishandley, @chicagogrrl)
153
+ * Add the :touch to update ancestors on save (thx @adammck)
154
+ * Change conditions into arel (thx @mlitwiniuk)
155
+ * Added children? & siblings? alias (thx @bigtunacan)
156
+ * closure_tree compatibility (thx @gzigzigzeo)
157
+ * Performance tweak (thx @mjc)
158
+ * Improvements to organization (thx @xsuchy, @ryakh)
159
+
160
+ ## Version [2.0.0] <sub><sup>2013-05-17</sub></sup>
161
+ * Removed rails 2 compatibility
162
+ * Added table name to condition constructing methods (thx @aflatter)
163
+ * Fix depth_cache not being updated when moving up to ancestors (thx @scottatron)
164
+ * add alias :root? to existing is_root? (thx @divineforest)
165
+ * Add block to sort_by_ancestry (thx @Iliya)
166
+ * Add attribute query method for parent_id (thx @sj26)
167
+ * Fixed and tested for rails 4 (thx @adammck, @Nihad, @Systho, @Philippe, e.a.)
168
+ * Fixed overwriting ActiveRecord::Base.base_class (thx @Rozhnov)
169
+ * New adopt strategy (thx unknown)
170
+ * Many more improvements
171
+
172
+ ## Version [1.3.0] <sub><sup>2012-05-04</sub></sup>
173
+ * Ancestry now ignores default scopes when moving or destroying nodes, ensuring tree consistency
174
+ * Changed ActiveRecord dependency to 2.3.14
175
+
176
+ ## Version [1.2.5] <sub><sup>2012-03-15</sub></sup>
177
+ * Fixed warnings: "parenthesize argument(s) for future version"
178
+ * Fixed a bug in the restore_ancestry_integrity! method (thx Arthur Holstvoogd)
179
+
180
+ ## Version [1.2.4] <sub><sup>2011-04-22</sub></sup>
181
+ * Prepended table names to column names in queries (thx @raelik)
182
+ * Better check to see if acts_as_tree can be overloaded (thx @jims)
183
+ * Performance inprovements (thx @kueda)
184
+
185
+ ## Version [1.2.3] <sub><sup>2010-10-28</sub></sup>
186
+ * Fixed error with determining ActiveRecord version
187
+ * Added option to specify :primary_key_format (thx @rolftimmermans)
188
+
189
+ ## Version [1.2.2] <sub><sup>2010-10-24</sub></sup>
190
+ * Fixed all deprecation warnings for rails 3.0.X
191
+ * Added `:report` option to `check_ancestry_integrity!`
192
+ * Changed ActiveRecord dependency to 2.2.2
193
+ * Tested and fixed for ruby 1.8.7 and 1.9.2
194
+ * Changed usage of `update_attributes` to `update_attribute` to allow ancestry column protection
195
+
196
+ ## Version [1.2.0] <sub><sup>2009-11-07</sub></sup>
197
+ * Removed some duplication in has_ancestry
198
+ * Cleaned up plugin pattern according to http://yehudakatz.com/2009/11/12/better-ruby-idioms/
199
+ * Moved parts of ancestry into seperate files
200
+ * Made it possible to pass options into the arrange method
201
+ * Renamed acts_as_tree to has_ancestry
202
+ * Aliased has_ancestry as acts_as_tree if acts_as_tree is available
203
+ * Added subtree_of scope
204
+ * Updated ordered_by_ancestry scope to support Microsoft SQL Server
205
+ * Added empty hash as parameter to exists? calls for older ActiveRecord versions
206
+
207
+ ## Version [1.1.4] <sub><sup>2009-11-07</sub></sup>
208
+ * Thanks to a patch from tom taylor, Ancestry now works with different primary keys
209
+
210
+ ## Version [1.1.3] <sub><sup>2009-11-01</sub></sup>
211
+ * Fixed a pretty bad bug where several operations took far too many queries
212
+
213
+ ## Version [1.1.2] <sub><sup>2009-10-29</sub></sup>
214
+ * Added validation for depth cache column
215
+ * Added STI support (reported broken)
216
+
217
+ ## Version [1.1.1] <sub><sup>2009-10-28</sub></sup>
218
+ * Fixed some parentheses warnings that where reported
219
+ * Fixed a reported issue with arrangement
220
+ * Fixed issues with ancestors and path order on postgres
221
+ * Added ordered_by_ancestry scope (needed to fix issues)
222
+
223
+ ## Version [1.1.0] <sub><sup>2009-10-22</sub></sup>
224
+ * Depth caching (and cache rebuilding)
225
+ * Depth method for nodes
226
+ * Named scopes for selecting by depth
227
+ * Relative depth options for tree navigation methods:
228
+ * ancestors
229
+ * path
230
+ * descendants
231
+ * descendant_ids
232
+ * subtree
233
+ * subtree_ids
234
+ * Updated README
235
+ * Easy migration from existing plugins/gems
236
+ * acts_as_tree checks unknown options
237
+ * acts_as_tree checks that options are hash
238
+ * Added a bang (!) to the integrity functions
239
+ * Since these functions should only be used from ./script/console and not
240
+ from your application, this change is not considered as breaking backwards
241
+ compatibility and the major version wasn't bumped.
242
+ * Updated install script to point to documentation
243
+ * Removed rails specific init
244
+ * Removed uninstall script
245
+
246
+ ## Version 1.0.0 <sub><sup>2009-10-16</sub></sup>
247
+ * Initial version
248
+ * Tree building
249
+ * Tree navigation
250
+ * Integrity checking / restoration
251
+ * Arrangement
252
+ * Orphan strategies
253
+ * Subtree movement
254
+ * Named scopes
255
+ * Validations
256
+
257
+
258
+ [HEAD]: https://github.com/stefankroes/ancestry/compare/v4.0.0...HEAD
259
+ [4.0.0]: https://github.com/stefankroes/ancestry/compare/v3.2.1...v4.0.0
260
+ [3.2.1]: https://github.com/stefankroes/ancestry/compare/v3.2.0...v3.2.1
261
+ [3.2.0]: https://github.com/stefankroes/ancestry/compare/v3.1.0...v3.2.0
262
+ [3.1.0]: https://github.com/stefankroes/ancestry/compare/v3.0.7...v3.1.0
263
+ [3.0.7]: https://github.com/stefankroes/ancestry/compare/v3.0.6...v3.0.7
264
+ [3.0.6]: https://github.com/stefankroes/ancestry/compare/v3.0.5...v3.0.6
265
+ [3.0.5]: https://github.com/stefankroes/ancestry/compare/v3.0.4...v3.0.5
266
+ [3.0.4]: https://github.com/stefankroes/ancestry/compare/v3.0.3...v3.0.4
267
+ [3.0.3]: https://github.com/stefankroes/ancestry/compare/v3.0.2...v3.0.3
268
+ [3.0.2]: https://github.com/stefankroes/ancestry/compare/v3.0.1...v3.0.2
269
+ [3.0.1]: https://github.com/stefankroes/ancestry/compare/v3.0.0...v3.0.1
270
+ [3.0.0]: https://github.com/stefankroes/ancestry/compare/v2.2.2...v3.0.0
271
+ [2.2.2]: https://github.com/stefankroes/ancestry/compare/v2.2.1...v2.2.2
272
+ [2.2.1]: https://github.com/stefankroes/ancestry/compare/v2.2.0...v2.2.1
273
+ [2.2.0]: https://github.com/stefankroes/ancestry/compare/v2.1.0...v2.2.0
274
+ [2.1.0]: https://github.com/stefankroes/ancestry/compare/v2.0.0...v2.1.0
275
+ [2.0.0]: https://github.com/stefankroes/ancestry/compare/v1.3.0...v2.0.0
276
+ [1.3.0]: https://github.com/stefankroes/ancestry/compare/v1.2.5...v1.3.0
277
+ [1.2.5]: https://github.com/stefankroes/ancestry/compare/v1.2.4...v1.2.5
278
+ [1.2.4]: https://github.com/stefankroes/ancestry/compare/v1.2.3...v1.2.4
279
+ [1.2.3]: https://github.com/stefankroes/ancestry/compare/v1.2.2...v1.2.3
280
+ [1.2.2]: https://github.com/stefankroes/ancestry/compare/v1.2.0...v1.2.2
281
+ [1.2.0]: https://github.com/stefankroes/ancestry/compare/v1.1.4...v1.2.0
282
+ [1.1.4]: https://github.com/stefankroes/ancestry/compare/v1.1.3...v1.1.4
283
+ [1.1.3]: https://github.com/stefankroes/ancestry/compare/v1.1.2...v1.1.3
284
+ [1.1.2]: https://github.com/stefankroes/ancestry/compare/v1.1.1...v1.1.2
285
+ [1.1.1]: https://github.com/stefankroes/ancestry/compare/v1.1.0...v1.1.1
286
+ [1.1.0]: https://github.com/stefankroes/ancestry/compare/v1.0.0...v1.1.0
data/README.md CHANGED
@@ -3,24 +3,24 @@
3
3
  # Ancestry
4
4
 
5
5
  Ancestry is a gem that allows the records of a Ruby on Rails
6
- ActiveRecord model to be organised as a tree structure (or hierarchy). It uses
7
- a single database column, using the materialised path pattern. It exposes all the standard tree structure
8
- relations (ancestors, parent, root, children, siblings, descendants) and all
9
- of them can be fetched in a single SQL query. Additional features are STI
6
+ ActiveRecord model to be organised as a tree structure (or hierarchy). It employs
7
+ the materialised path pattern and exposes all the standard tree structure
8
+ relations (ancestors, parent, root, children, siblings, descendants), allowing all
9
+ of them to be fetched in a single SQL query. Additional features include STI
10
10
  support, scopes, depth caching, depth constraints, easy migration from older
11
11
  gems, integrity checking, integrity restoration, arrangement of
12
- (sub)tree into hashes and different strategies for dealing with orphaned
12
+ (sub)trees into hashes, and various strategies for dealing with orphaned
13
13
  records.
14
14
 
15
15
  NOTE:
16
16
 
17
- - Ancestry 3.x supports Rails 5.0 and earlier.
17
+ - Ancestry 2.x supports Rails 4.1 and earlier
18
+ - Ancestry 3.x supports Rails 5.0 and 4.2
18
19
  - Ancestry 4.0 only supports rails 5.0 and higher
19
20
 
20
21
  # Installation
21
22
 
22
- To apply Ancestry to any `ActiveRecord` model, follow these simple steps:
23
-
23
+ Follow these simple steps to apply Ancestry to any ActiveRecord model:
24
24
 
25
25
  ## Install
26
26
 
@@ -54,7 +54,7 @@ $ rake db:migrate
54
54
 
55
55
 
56
56
  ## Add ancestry to your model
57
- * Add to [app/models/](model).rb:
57
+ * Add to app/models/[model.rb]:
58
58
 
59
59
  ```ruby
60
60
  # app/models/[model.rb]
@@ -68,9 +68,9 @@ Your model is now a tree!
68
68
 
69
69
  # Using acts_as_tree instead of has_ancestry
70
70
 
71
- In version 1.2.0 the **acts_as_tree** method was **renamed to has_ancestry**
71
+ In version 1.2.0, the **acts_as_tree** method was **renamed to has_ancestry**
72
72
  in order to allow usage of both the acts_as_tree gem and the ancestry gem in a
73
- single application. method `acts_as_tree` will continue to be supported in the future.
73
+ single application. The `acts_as_tree` method will continue to be supported in the future.
74
74
 
75
75
  # Organising records into a tree
76
76
 
@@ -81,64 +81,38 @@ parent_id can be set using parent= and parent_id= on a record or by including
81
81
  them in the hash passed to new, create, create!, update_attributes and
82
82
  update_attributes!. For example:
83
83
 
84
- ```ruby
85
- TreeNode.create! :name => 'Stinky', :parent => TreeNode.create!(:name => 'Squeeky')
86
- ```
84
+ `TreeNode.create! :name => 'Stinky', :parent => TreeNode.create!(:name => 'Squeeky')`.
87
85
 
88
- You can also create children through the children relation on a node:
86
+ Children can be created through the children relation on a node: `node.children.create :name => 'Stinky'`.
89
87
 
90
- ```ruby
91
- node.children.create :name => 'Stinky'
92
- ```
88
+ # Tree Navigation
89
+
90
+ The node with the large border is the reference node (the node from which the navigation method is invoked.)
91
+ The yellow nodes are those returned by the method.
92
+
93
+ | | | |
94
+ |:-: |:-: |:-: |
95
+ |**parent** |**root**<sup><a href="#fn1" id="ref1">1</a></sup> |**ancestors** |
96
+ |![parent](/img/parent.png) |![root](/img/root.png) |![ancestors](/img/ancestors.png) |
97
+ | nil for a root node |self for a root node |root..parent |
98
+ | `parent_id` |`root_id` |`ancestor_ids` |
99
+ | `has_parent?` |`is_root?` |`ancestors?` |
100
+ |`parent_of?` |`root_of?` |`ancestor_of?` |
101
+ |**children** |**descendants** |**indirects** |
102
+ |![children](/img/children.png) |![descendants](/img/descendants.png) |![indirects](/img/indirects.png) |
103
+ | `child_ids` |`descendant_ids` |`indirect_ids` |
104
+ | `has_children?` | | |
105
+ | `child_of?` |`descendant_of?` |`indirect_of?` |
106
+ |**siblings** |**subtree** |**path** |
107
+ |![siblings](/img/siblings.png) |![subtree](/img/subtree.png) |![path](/img/path.png) |
108
+ | includes self |self..indirects |root..self |
109
+ |`sibling_ids` |`subtree_ids` |`path_ids` |
110
+ |`has_siblings?` | | |
111
+ |`sibling_of?(node)` | | |
93
112
 
94
- # Navigating your tree
95
-
96
- To navigate an Ancestry model, use the following instance methods:
97
-
98
- | method |return value|
99
- |-------------------|------------|
100
- |`parent` |parent of the record, nil for a root node|
101
- |`parent_id` |parent id of the record, nil for a root node|
102
- |`root` |root of the record's tree, self for a root node|
103
- |`root_id` |root id of the record's tree, self for a root node|
104
- |`root?` <br/> `is_root?` | true if the record is a root node, false otherwise|
105
- |`ancestors` |ancestors of the record, starting with the root and ending with the parent|
106
- |`ancestors?` |true if the record has ancestors (aka not a root node)|
107
- |`ancestor_ids` |ancestor ids of the record|
108
- |`path` |path of the record, starting with the root and ending with self|
109
- |`path_ids` |a list the path ids, starting with the root id and ending with the node's own id|
110
- |`children` |direct children of the record|
111
- |`child_ids` |direct children's ids|
112
- |`has_parent?` <br/> `ancestors?` |true if the record has a parent, false otherwise|
113
- |`has_children?` <br/> `children?` |true if the record has any children, false otherwise|
114
- |`is_childless?` <br/> `childless?` |true is the record has no children, false otherwise|
115
- |`siblings` |siblings of the record, the record itself is included*|
116
- |`sibling_ids` |sibling ids|
117
- |`has_siblings?` <br/> `siblings?` |true if the record's parent has more than one child|
118
- |`is_only_child?` <br/> `only_child?` |true if the record is the only child of its parent|
119
- |`descendants` |direct and indirect children of the record|
120
- |`descendant_ids` |direct and indirect children's ids of the record|
121
- |`indirects` |indirect children of the record|
122
- |`indirect_ids` |indirect children's ids of the record|
123
- |`subtree` |the model on descendants and itself|
124
- |`subtree_ids` |a list of all ids in the record's subtree|
125
- |`depth` |the depth of the node, root nodes are at depth 0|
126
-
127
- \* If the record is a root, other root records are considered siblings
128
- \* Siblings returns the record itself
129
-
130
- There are also instance methods to determine the relationship between 2 nodes:
131
-
132
- |method |return value|
133
- |-------------------|---------------|
134
- |`parent_of?(node)` | node's parent is this record|
135
- |`root_of?(node)` | node's root is this record|
136
- |`ancestor_of?(node)`| node's ancestors include this record|
137
- |`child_of?(node)` | node is record's parent|
138
- |`descendant_of?(node)` | node is one of this record's ancestors|
139
- |`indirect_of?(node)` | node is one of this record's ancestors but not a parent|
140
-
141
- # Options for `has_ancestry`
113
+ <sup id="fn1">1. [other root records are considered siblings]<a href="#ref1" title="Jump back to footnote 1.">↩</a></sup>
114
+
115
+ # `has_ancestry` options
142
116
 
143
117
  The has_ancestry method supports the following options:
144
118
 
@@ -147,24 +121,25 @@ The has_ancestry method supports the following options:
147
121
  :destroy All children are destroyed as well (default)
148
122
  :rootify The children of the destroyed node become root nodes
149
123
  :restrict An AncestryException is raised if any children exist
150
- :adopt The orphan subtree is added to the parent of the deleted node.
151
- If the deleted node is Root, then rootify the orphan subtree.
124
+ :adopt The orphan subtree is added to the parent of the deleted node
125
+ If the deleted node is Root, then rootify the orphan subtree
152
126
  :cache_depth Cache the depth of each node in the 'ancestry_depth' column (default: false)
153
127
  If you turn depth_caching on for an existing model:
154
128
  - Migrate: add_column [table], :ancestry_depth, :integer, :default => 0
155
129
  - Build cache: TreeNode.rebuild_depth_cache!
156
130
  :depth_cache_column Pass in a symbol to store depth cache in a different column
157
- :primary_key_format Supply a regular expression that matches the format of your primary key.
158
- By default, primary keys only match integers ([0-9]+).
131
+ :primary_key_format Supply a regular expression that matches the format of your primary key
132
+ By default, primary keys only match integers ([0-9]+)
159
133
  :touch Instruct Ancestry to touch the ancestors of a node when it changes, to
160
134
  invalidate nested key-based caches. (default: false)
135
+ :counter_cache Boolean whether to create counter cache column accessor.
136
+ Default column name is `children_count`.
137
+ Pass symbol to use different column name (default: false)
161
138
 
162
139
  # (Named) Scopes
163
140
 
164
- Where possible, the navigation methods return scopes instead of records, this
165
- means additional ordering, conditions, limits, etc. can be applied and that
166
- the result can be either retrieved, counted or checked for existence. For
167
- example:
141
+ The navigation methods return scopes instead of records, where possible. Additional ordering,
142
+ conditions, limits, etc. can be applied and the results can be retrieved, counted, or checked for existence:
168
143
 
169
144
  ```ruby
170
145
  node.children.where(:name => 'Mary').exists?
@@ -172,7 +147,7 @@ node.subtree.order(:name).limit(10).each { ... }
172
147
  node.descendants.count
173
148
  ```
174
149
 
175
- For convenience, a couple of named scopes are included at the class level:
150
+ A couple of class-level named scopes are included:
176
151
 
177
152
  roots Root nodes
178
153
  ancestors_of(node) Ancestors of node, node can be either a record or an id
@@ -182,8 +157,7 @@ For convenience, a couple of named scopes are included at the class level:
182
157
  subtree_of(node) Subtree of node, node can be either a record or an id
183
158
  siblings_of(node) Siblings of node, node can be either a record or an id
184
159
 
185
- Thanks to some convenient rails magic, it is even possible to create nodes
186
- through the children and siblings scopes:
160
+ It is possible thanks to some convenient rails magic to create nodes through the children and siblings scopes:
187
161
 
188
162
  node.children.create
189
163
  node.siblings.create!
@@ -192,8 +166,8 @@ through the children and siblings scopes:
192
166
 
193
167
  # Selecting nodes by depth
194
168
 
195
- When depth caching is enabled (see has_ancestry options), five more named
196
- scopes can be used to select nodes on their depth:
169
+ With depth caching enabled (see has_ancestry options), an additional five named
170
+ scopes can be used to select nodes by depth:
197
171
 
198
172
  before_depth(depth) Return nodes that are less deep than depth (node.depth < depth)
199
173
  to_depth(depth) Return nodes up to a certain depth (node.depth <= depth)
@@ -201,42 +175,27 @@ scopes can be used to select nodes on their depth:
201
175
  from_depth(depth) Return nodes starting from a certain depth (node.depth >= depth)
202
176
  after_depth(depth) Return nodes that are deeper than depth (node.depth > depth)
203
177
 
204
- The depth scopes are also available through calls to descendants,
205
- descendant_ids, subtree, subtree_ids, path and ancestors. In this case, depth
206
- values are interpreted relatively. Some examples:
207
-
208
- node.subtree(:to_depth => 2) Subtree of node, to a depth of node.depth + 2 (self, children and grandchildren)
209
- node.subtree.to_depth(5) Subtree of node to an absolute depth of 5
210
- node.descendants(:at_depth => 2) Descendant of node, at depth node.depth + 2 (grandchildren)
211
- node.descendants.at_depth(10) Descendants of node at an absolute depth of 10
212
- node.ancestors.to_depth(3) The oldest 4 ancestors of node (its root and 3 more)
213
- node.path(:from_depth => -2) The node's grandparent, parent and the node itself
178
+ Depth scopes are also available through calls to `descendants`,
179
+ `descendant_ids`, `subtree`, `subtree_ids`, `path` and `ancestors` (with relative depth).
180
+ Note that depth constraints cannot be passed to `ancestor_ids` or `path_ids` as both relations
181
+ can be fetched directly from the ancestry column without needing a query. Use
182
+ `ancestors(depth_options).map(&:id)` or `ancestor_ids.slice(min_depth..max_depth)` instead.
214
183
 
215
184
  node.ancestors(:from_depth => -6, :to_depth => -4)
216
185
  node.path.from_depth(3).to_depth(4)
217
186
  node.descendants(:from_depth => 2, :to_depth => 4)
218
187
  node.subtree.from_depth(10).to_depth(12)
219
188
 
220
- Please note that depth constraints cannot be passed to ancestor_ids and
221
- path_ids. The reason for this is that both these relations can be fetched
222
- directly from the ancestry column without performing a database query. It
223
- would require an entirely different method of applying the depth constraints
224
- which isn't worth the effort of implementing. You can use
225
- ancestors(depth_options).map(&:id) or ancestor_ids.slice(min_depth..max_depth)
226
- instead.
227
-
228
189
  # STI support
229
190
 
230
- Ancestry works fine with STI. Just create a STI inheritance hierarchy and
231
- build an Ancestry tree from the different classes/models. All Ancestry
232
- relations that were described above will return nodes of any model type. If
233
- you do only want nodes of a specific subclass you'll have to add a condition
234
- on type for that.
191
+ To use with STI: create a STI inheritance hierarchy and build a tree from the different
192
+ classes/models. All Ancestry relations that were described above will return nodes of any model type. If
193
+ you do only want nodes of a specific subclass, a type condition is required.
235
194
 
236
195
  # Arrangement
237
196
 
238
- Ancestry can arrange an entire subtree into nested hashes for easy navigation
239
- after retrieval from the database. TreeNode.arrange could for example return:
197
+ A subtree can be arranged into nested hashes for easy navigation after database retrieval.
198
+ `TreeNode.arrange` could, for instance, return:
240
199
 
241
200
  ```ruby
242
201
  {
@@ -249,43 +208,20 @@ after retrieval from the database. TreeNode.arrange could for example return:
249
208
  }
250
209
  ```
251
210
 
252
- The arrange method also works on a scoped class, for example:
253
-
254
- ```ruby
255
- TreeNode.find_by_name('Crunchy').subtree.arrange
256
- ```
257
-
258
- The arrange method takes `ActiveRecord` find options. If you want your hashes to
259
- be ordered, you should pass the order to the arrange method instead of to the
260
- scope. example:
211
+ The `arrange` method can work on a scoped class (`TreeNode.find_by(:name => 'Crunchy').subtree.arrange`),
212
+ and can take ActiveRecord find options. If you want ordered hashes, pass the order to the method instead of
213
+ the scope as follows:
261
214
 
262
- ```ruby
263
- TreeNode.find_by_name('Crunchy').subtree.arrange(:order => :name)
264
- ```
215
+ `TreeNode.find_by(:name => 'Crunchy').subtree.arrange(:order => :name)`.
265
216
 
266
- To get the arranged nodes as a nested array of hashes for serialization:
217
+ The `arrange_serializable` method returns the arranged nodes as a nested array of hashes. Order
218
+ can be passed in the same fashion as to the `arrange` method:
219
+ `TreeNode.arrange_serializable(:order => :name)` The result can easily be serialized to json with `to_json`
220
+ or other formats. You can also supply your own serialization logic with blocks.
267
221
 
268
- TreeNode.arrange_serializable
222
+ Using `ActiveModel` serializers:
269
223
 
270
- ```ruby
271
- [
272
- {
273
- "ancestry" => nil, "id" => 1, "children" => [
274
- { "ancestry" => "1", "id" => 2, "children" => [] }
275
- ]
276
- }
277
- ]
278
- ```
279
-
280
- You can also supply your own serialization logic using blocks:
281
-
282
- For example, using `ActiveModel` Serializers:
283
-
284
- ```ruby
285
- TreeNode.arrange_serializable do |parent, children|
286
- MySerializer.new(parent, children: children)
287
- end
288
- ```
224
+ `TreeNode.arrange_serializable { |parent, children| MySerializer.new(parent, children: children) }`.
289
225
 
290
226
  Or plain hashes:
291
227
 
@@ -298,39 +234,22 @@ TreeNode.arrange_serializable do |parent, children|
298
234
  end
299
235
  ```
300
236
 
301
- The result of arrange_serializable can easily be serialized to json with
302
- `to_json`, or some other format:
303
-
304
- ```
305
- TreeNode.arrange_serializable.to_json
306
- ```
307
-
308
- You can also pass the order to the arrange_serializable method just as you can
309
- pass it to the arrange method:
310
-
311
- ```
312
- TreeNode.arrange_serializable(:order => :name)
313
- ```
314
-
315
237
  # Sorting
316
238
 
317
- If you just want to sort an array of nodes as if you were traversing them in
318
- preorder, you can use the sort_by_ancestry class method:
319
-
320
- ```
321
- TreeNode.sort_by_ancestry(array_of_nodes)
322
- ```
323
-
324
- Note that since materialised path trees don't support ordering within a rank,
325
- the order of siblings depends on their order in the original array.
239
+ The `sort_by_ancestry` class method: `TreeNode.sort_by_ancestry(array_of_nodes)` can be used
240
+ to sort an array of nodes as if traversing in preorder. (Note that since materialised path
241
+ trees do not support ordering within a rank, the order of siblings is
242
+ dependant upon their original array order.)
326
243
 
327
244
  # Migrating from plugin that uses parent_id column
328
245
 
329
246
  Most current tree plugins use a parent_id column (has_ancestry,
330
- awesome_nested_set, better_nested_set, acts_as_nested_set). With ancestry it is
331
- easy to migrate from any of these plugins, to do so, use the
332
- build_ancestry_from_parent_ids! method on your ancestry model. These steps
333
- provide a more detailed explanation:
247
+ awesome_nested_set, better_nested_set, acts_as_nested_set). With Ancestry it is
248
+ easy to migrate from any of these plugins. To do so, use the
249
+ `build_ancestry_from_parent_ids!` method on your ancestry model.
250
+
251
+ <details>
252
+ <summary>Details</summary>
334
253
 
335
254
  1. Add ancestry column to your table
336
255
  * Create migration: **rails g migration [add_ancestry_to_](table)
@@ -340,7 +259,7 @@ provide a more detailed explanation:
340
259
  * Migrate your database: **rake db:migrate**
341
260
 
342
261
 
343
- 2. Remove old tree gem and add in Ancestry to `Gemfile`
262
+ 2. Remove old tree gem and add in Ancestry to Gemfile
344
263
  * See 'Installation' for more info on installing and configuring gems
345
264
 
346
265
 
@@ -351,7 +270,7 @@ provide a more detailed explanation:
351
270
 
352
271
 
353
272
  4. Generate ancestry columns
354
- * In './script.console': **[model].build_ancestry_from_parent_ids!**
273
+ * In rails console: **[model].build_ancestry_from_parent_ids!**
355
274
  * Make sure it worked ok: **[model].check_ancestry_integrity!**
356
275
 
357
276
 
@@ -365,42 +284,7 @@ provide a more detailed explanation:
365
284
  * Create migration: `rails g migration [remove_parent_id_from_](table)`
366
285
  * Add to migration: `remove_column [table], :parent_id`
367
286
  * Migrate your database: `rake db:migrate`
368
-
369
- # Integrity checking and restoration
370
-
371
- I don't see any way Ancestry tree integrity could get compromised without
372
- explicitly setting cyclic parents or invalid ancestry and circumventing
373
- validation with update_attribute, if you do, please let me know.
374
-
375
- Ancestry includes some methods for detecting integrity problems and restoring
376
- integrity just to be sure. To check integrity use:
377
- [Model].check_ancestry_integrity!. An AncestryIntegrityException will be
378
- raised if there are any problems. You can also specify :report => :list to
379
- return an array of exceptions or :report => :echo to echo any error messages.
380
- To restore integrity use: [Model].restore_ancestry_integrity!.
381
-
382
- For example, from IRB:
383
-
384
- ```
385
- >> stinky = TreeNode.create :name => 'Stinky'
386
- $ #<TreeNode id: 1, name: "Stinky", ancestry: nil>
387
- >> squeeky = TreeNode.create :name => 'Squeeky', :parent => stinky
388
- $ #<TreeNode id: 2, name: "Squeeky", ancestry: "1">
389
- >> stinky.update_attribute :parent, squeeky
390
- $ true
391
- >> TreeNode.all
392
- $ [#<TreeNode id: 1, name: "Stinky", ancestry: "1/2">, #<TreeNode id: 2, name: "Squeeky", ancestry: "1/2/1">]
393
- >> TreeNode.check_ancestry_integrity!
394
- !! Ancestry::AncestryIntegrityException: Conflicting parent id in node 1: 2 for node 1, expecting nil
395
- >> TreeNode.restore_ancestry_integrity!
396
- $ [#<TreeNode id: 1, name: "Stinky", ancestry: 2>, #<TreeNode id: 2, name: "Squeeky", ancestry: nil>]
397
- ```
398
-
399
- Additionally, if you think something is wrong with your depth cache:
400
-
401
- ```
402
- >> TreeNode.rebuild_depth_cache!
403
- ```
287
+ </details>
404
288
 
405
289
  # Running Tests
406
290