closure_tree 3.6.0 → 3.6.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|