closure_tree 3.6.0 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +30 -20
- data/lib/closure_tree/acts_as_tree.rb +13 -6
- data/lib/closure_tree/version.rb +1 -1
- data/spec/label_spec.rb +45 -0
- metadata +3 -3
data/README.md
CHANGED
@@ -23,7 +23,7 @@ for a description of different tree storage algorithms.
|
|
23
23
|
- [Installation](#installation)
|
24
24
|
- [Usage](#usage)
|
25
25
|
- [Accessing Data](#accessing-data)
|
26
|
-
- [Polymorphic hierarchies with STI](#sti)
|
26
|
+
- [Polymorphic hierarchies with STI](#polymorphic-hierarchies-with-sti)
|
27
27
|
- [Deterministic ordering](#deterministic-ordering)
|
28
28
|
- [FAQ](#faq)
|
29
29
|
- [Testing](#testing)
|
@@ -247,7 +247,7 @@ When you include ```acts_as_tree``` in your model, you can provide a hash to ove
|
|
247
247
|
* ```tag.find_all_by_generation(2)``` will return the tag's grandchildren, and so on.
|
248
248
|
* ```tag.destroy``` will destroy a node and do <em>something</em> to its children, which is determined by the ```:dependent``` option passed to ```acts_as_tree```.
|
249
249
|
|
250
|
-
##
|
250
|
+
## Polymorphic hierarchies with STI
|
251
251
|
|
252
252
|
Polymorphic models using single table inheritance (STI) are supported:
|
253
253
|
|
@@ -300,37 +300,40 @@ When you enable ```order```, you'll also have the following new methods injected
|
|
300
300
|
|
301
301
|
If your ```order``` column is an integer attribute, you'll also have these:
|
302
302
|
|
303
|
-
* ```
|
304
|
-
1.
|
305
|
-
2.
|
306
|
-
3.
|
303
|
+
* ```node1.prepend_sibling(node2)``` which will
|
304
|
+
1. set ```node2``` to the same parent as ```node1```,
|
305
|
+
2. set ```node2```'s order column to 1 less than ```node1```'s value, and
|
306
|
+
3. decrement the order_column of all children of node1's parents whose order_column is <>>= node2's new value by 1.
|
307
307
|
|
308
|
-
* ```
|
309
|
-
1.
|
310
|
-
2.
|
311
|
-
3.
|
308
|
+
* ```node1.append_sibling(node2)``` which will
|
309
|
+
1. set ```node2``` to the same parent as ```node1```,
|
310
|
+
2. set ```node2```'s order column to 1 more than ```node1```'s value, and
|
311
|
+
3. increment the order_column of all children of node1's parents whose order_column is >= node2's new value by 1.
|
312
312
|
|
313
313
|
```ruby
|
314
|
+
|
314
315
|
root = OrderedTag.create(:name => "root")
|
315
316
|
a = OrderedTag.create(:name => "a", :parent => "root")
|
316
317
|
b = OrderedTag.create(:name => "b")
|
317
318
|
c = OrderedTag.create(:name => "c")
|
318
319
|
|
320
|
+
# We have to call 'root.reload.children' because root won't be in sync with the database otherwise:
|
321
|
+
|
319
322
|
a.append_sibling(b)
|
320
|
-
root.children.collect(&:name)
|
323
|
+
root.reload.children.collect(&:name)
|
321
324
|
=> ["a", "b"]
|
322
325
|
|
323
326
|
a.prepend_sibling(b)
|
324
|
-
root.children.collect(&:name)
|
327
|
+
root.reload.children.collect(&:name)
|
325
328
|
=> ["b", "a"]
|
326
329
|
|
327
330
|
a.append_sibling(c)
|
328
|
-
root.children.collect(&:name)
|
329
|
-
=> ["
|
331
|
+
root.reload.children.collect(&:name)
|
332
|
+
=> ["b", "a", "c"]
|
330
333
|
|
331
334
|
b.append_sibling(c)
|
332
|
-
root.children.collect(&:name)
|
333
|
-
=> ["
|
335
|
+
root.reload.children.collect(&:name)
|
336
|
+
=> ["b", "c", "a"]
|
334
337
|
```
|
335
338
|
|
336
339
|
## FAQ
|
@@ -352,12 +355,19 @@ Closure tree is [tested under every combination](http://travis-ci.org/#!/mceache
|
|
352
355
|
|
353
356
|
## Change log
|
354
357
|
|
358
|
+
### 3.6.1
|
359
|
+
|
360
|
+
* Fixed [issue 20](https://github.com/mceachen/closure_tree/issues/20), which affected
|
361
|
+
deterministic ordering when siblings where different STI classes. Thanks, [edwinramirez](https://github.com/edwinramirez)!
|
362
|
+
|
355
363
|
### 3.6.0
|
356
364
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
365
|
+
Added support for:
|
366
|
+
* ```:hierarchy_class_name``` as an option
|
367
|
+
* ActiveRecord::Base.table_name_prefix
|
368
|
+
* ActiveRecord::Base.table_name_suffix
|
369
|
+
|
370
|
+
This addresses [issue 21](https://github.com/mceachen/closure_tree/issues/21). Thanks, [Judd Blair](https://github.com/juddblair)!
|
361
371
|
|
362
372
|
### 3.5.2
|
363
373
|
|
@@ -5,6 +5,7 @@ module ClosureTree
|
|
5
5
|
class_attribute :closure_tree_options
|
6
6
|
|
7
7
|
self.closure_tree_options = {
|
8
|
+
:ct_base_class => self,
|
8
9
|
:parent_column_name => 'parent_id',
|
9
10
|
:dependent => :nullify, # or :destroy or :delete_all -- see the README
|
10
11
|
:name_column => 'name'
|
@@ -180,7 +181,7 @@ module ClosureTree
|
|
180
181
|
end
|
181
182
|
|
182
183
|
def self_and_siblings
|
183
|
-
s =
|
184
|
+
s = ct_base_class.where(parent_column_sym => parent)
|
184
185
|
quoted_order_column ? s.order(quoted_order_column) : s
|
185
186
|
end
|
186
187
|
|
@@ -228,14 +229,14 @@ module ClosureTree
|
|
228
229
|
end
|
229
230
|
|
230
231
|
def find_all_by_generation(generation_level)
|
231
|
-
s =
|
232
|
+
s = ct_base_class.joins(<<-SQL)
|
232
233
|
INNER JOIN (
|
233
234
|
SELECT descendant_id
|
234
235
|
FROM #{quoted_hierarchy_table_name}
|
235
236
|
WHERE ancestor_id = #{self.id}
|
236
237
|
GROUP BY 1
|
237
238
|
HAVING MAX(#{quoted_hierarchy_table_name}.generations) = #{generation_level.to_i}
|
238
|
-
) AS descendants ON (#{quoted_table_name}.#{
|
239
|
+
) AS descendants ON (#{quoted_table_name}.#{ct_base_class.primary_key} = descendants.descendant_id)
|
239
240
|
SQL
|
240
241
|
order_option ? s.order(order_option) : s
|
241
242
|
end
|
@@ -317,7 +318,7 @@ module ClosureTree
|
|
317
318
|
end
|
318
319
|
|
319
320
|
def without_self(scope)
|
320
|
-
scope.where(["#{quoted_table_name}.#{
|
321
|
+
scope.where(["#{quoted_table_name}.#{ct_base_class.primary_key} != ?", self])
|
321
322
|
end
|
322
323
|
|
323
324
|
def ids_from(scope)
|
@@ -433,6 +434,11 @@ module ClosureTree
|
|
433
434
|
(self.is_a?(Class) ? self : self.class)
|
434
435
|
end
|
435
436
|
|
437
|
+
# This is the "topmost" class. This will only potentially not be ct_class if you are using STI.
|
438
|
+
def ct_base_class
|
439
|
+
ct_class.closure_tree_options[:ct_base_class]
|
440
|
+
end
|
441
|
+
|
436
442
|
def ct_subclass?
|
437
443
|
ct_class != ct_class.base_class
|
438
444
|
end
|
@@ -516,7 +522,8 @@ module ClosureTree
|
|
516
522
|
# We need to incr the before_siblings to make room for sibling_node:
|
517
523
|
if use_update_all
|
518
524
|
col = quoted_order_column(false)
|
519
|
-
|
525
|
+
# issue 21: we have to use the base class, so STI doesn't get in the way of only updating the child class instances:
|
526
|
+
ct_base_class.update_all(
|
520
527
|
["#{col} = #{col} #{add_after ? '+' : '-'} 1", "updated_at = now()"],
|
521
528
|
["#{quoted_parent_column_name} = ? AND #{col} #{add_after ? '>=' : '<='} ?",
|
522
529
|
ct_parent_id,
|
@@ -531,7 +538,7 @@ module ClosureTree
|
|
531
538
|
end
|
532
539
|
sibling_node.parent = self.parent
|
533
540
|
sibling_node.save!
|
534
|
-
sibling_node.reload
|
541
|
+
sibling_node.reload # <- because siblings_before and siblings_after will have changed.
|
535
542
|
end
|
536
543
|
end
|
537
544
|
end
|
data/lib/closure_tree/version.rb
CHANGED
data/spec/label_spec.rb
CHANGED
@@ -115,6 +115,51 @@ describe Label do
|
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
118
|
+
context "deterministically orders with polymorphic siblings" do
|
119
|
+
before :each do
|
120
|
+
@parent = Label.create!(:name => "parent")
|
121
|
+
@a = EventLabel.new(:name => "a")
|
122
|
+
@b = DirectoryLabel.new(:name => "b")
|
123
|
+
@c = DateLabel.new(:name => "c")
|
124
|
+
@parent.children << @a
|
125
|
+
@a.append_sibling(@b)
|
126
|
+
@b.append_sibling(@c)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "when inserted before" do
|
130
|
+
@b.append_sibling(@a)
|
131
|
+
# Have to reload because the sort_order will have changed out from under the references:
|
132
|
+
@b.reload.sort_order.should be < @a.reload.sort_order
|
133
|
+
@a.reload.sort_order.should be < @c.reload.sort_order
|
134
|
+
end
|
135
|
+
|
136
|
+
it "when inserted before" do
|
137
|
+
@b.append_sibling(@a, use_update_all = false)
|
138
|
+
# Have to reload because the sort_order will have changed out from under the references:
|
139
|
+
@b.reload.sort_order.should be < @a.reload.sort_order
|
140
|
+
@a.reload.sort_order.should be < @c.reload.sort_order
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
it "behaves like the readme" do
|
145
|
+
root = Label.create(:name => "root")
|
146
|
+
a = Label.create(:name => "a", :parent => root)
|
147
|
+
b = Label.create(:name => "b")
|
148
|
+
c = Label.create(:name => "c")
|
149
|
+
|
150
|
+
a.append_sibling(b)
|
151
|
+
root.reload.children.collect(&:name).should == %w(a b)
|
152
|
+
|
153
|
+
a.prepend_sibling(b)
|
154
|
+
root.reload.children.collect(&:name).should == %w(b a)
|
155
|
+
|
156
|
+
a.append_sibling(c)
|
157
|
+
root.reload.children.collect(&:name).should == %w(b a c)
|
158
|
+
|
159
|
+
b.append_sibling(c)
|
160
|
+
root.reload.children.collect(&:name).should == %w(b c a)
|
161
|
+
end
|
162
|
+
|
118
163
|
context "Deterministic siblings sort with custom integer column" do
|
119
164
|
nuke_db
|
120
165
|
fixtures :labels
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: closure_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.6.
|
4
|
+
version: 3.6.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -192,7 +192,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
192
192
|
version: '0'
|
193
193
|
segments:
|
194
194
|
- 0
|
195
|
-
hash:
|
195
|
+
hash: 4291018222933120120
|
196
196
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
197
|
none: false
|
198
198
|
requirements:
|
@@ -201,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
201
201
|
version: '0'
|
202
202
|
segments:
|
203
203
|
- 0
|
204
|
-
hash:
|
204
|
+
hash: 4291018222933120120
|
205
205
|
requirements: []
|
206
206
|
rubyforge_project:
|
207
207
|
rubygems_version: 1.8.23
|