Skip to content

Commit 83193bd

Browse files
apply patch for root ordering scope (ClosureTree#442)
1 parent 9a15ec4 commit 83193bd

File tree

8 files changed

+70
-9
lines changed

8 files changed

+70
-9
lines changed

lib/closure_tree/has_closure_tree.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ def has_closure_tree(options = {})
1111
:dont_order_roots,
1212
:numeric_order,
1313
:touch,
14-
:with_advisory_lock
14+
:with_advisory_lock,
15+
:order_belong_to
1516
)
1617

1718
class_attribute :_ct

lib/closure_tree/model.rb

+4
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ def _ct_parent_id
171171
read_attribute(_ct.parent_column_sym)
172172
end
173173

174+
def _ct_belong_to_id
175+
read_attribute(_ct.belong_to_column_sym)
176+
end
177+
174178
def _ct_quoted_parent_id
175179
_ct.quoted_value(_ct_parent_id)
176180
end

lib/closure_tree/numeric_deterministic_ordering.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ def _ct_reorder_prior_siblings_if_parent_changed
1717
attribute_method = as_5_1 ? :attribute_before_last_save : :attribute_was
1818

1919
was_parent_id = public_send(attribute_method, _ct.parent_column_name)
20-
_ct.reorder_with_parent_id(was_parent_id)
20+
_ct.reorder_with_parent_id(parent_id: was_parent_id, belong_to_name: _ct.belong_to_column_sym, belong_to_id: _ct_belong_to_id)
2121
end
2222
end
2323

2424
def _ct_reorder_siblings(minimum_sort_order_value = nil)
25-
_ct.reorder_with_parent_id(_ct_parent_id, minimum_sort_order_value)
25+
_ct.reorder_with_parent_id(parent_id: _ct_parent_id, minimum_sort_order_value: minimum_sort_order_value, belong_to_name: _ct.belong_to_column_sym, belong_to_id: _ct_belong_to_id)
2626
reload unless destroyed?
2727
end
2828

2929
def _ct_reorder_children(minimum_sort_order_value = nil)
30-
_ct.reorder_with_parent_id(_ct_id, minimum_sort_order_value)
30+
_ct.reorder_with_parent_id(parent_id: _ct_id, minimum_sort_order_value: minimum_sort_order_value)
3131
end
3232

3333
def self_and_descendants_preordered

lib/closure_tree/numeric_order_support.rb

+16-5
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,48 @@ def self.adapter_for_connection(connection)
1313
end
1414

1515
module MysqlAdapter
16-
def reorder_with_parent_id(parent_id, minimum_sort_order_value = nil)
16+
def reorder_with_parent_id(parent_id:, minimum_sort_order_value: nil, belong_to_name: nil, belong_to_id: nil)
1717
return if parent_id.nil? && dont_order_roots
1818
min_where = if minimum_sort_order_value
1919
"AND #{quoted_order_column} >= #{minimum_sort_order_value}"
2020
else
2121
""
2222
end
23+
belong_to_scope = if parent_id.nil? && belong_to_id
24+
"AND #{quoted_table_name}.#{belong_to_name} = #{belong_to_id}"
25+
else
26+
""
27+
end
2328
connection.execute 'SET @i = 0'
2429
connection.execute <<-SQL.squish
2530
UPDATE #{quoted_table_name}
2631
SET #{quoted_order_column} = (@i := @i + 1) + #{minimum_sort_order_value.to_i - 1}
27-
WHERE #{where_eq(parent_column_name, parent_id)} #{min_where}
32+
WHERE #{where_eq(parent_column_name, parent_id)} #{min_where} #{belong_to_scope}
2833
ORDER BY #{nulls_last_order_by}
2934
SQL
3035
end
3136
end
3237

3338
module PostgreSQLAdapter
34-
def reorder_with_parent_id(parent_id, minimum_sort_order_value = nil)
39+
def reorder_with_parent_id(parent_id:, minimum_sort_order_value: nil, belong_to_name: nil, belong_to_id: nil)
3540
return if parent_id.nil? && dont_order_roots
3641
min_where = if minimum_sort_order_value
3742
"AND #{quoted_order_column} >= #{minimum_sort_order_value}"
3843
else
3944
""
4045
end
46+
belong_to_scope = if parent_id.nil? && belong_to_id
47+
"AND #{quoted_table_name}.#{belong_to_name} = #{belong_to_id}"
48+
else
49+
""
50+
end
4151
connection.execute <<-SQL.squish
4252
UPDATE #{quoted_table_name}
4353
SET #{quoted_order_column(false)} = t.seq + #{minimum_sort_order_value.to_i - 1}
4454
FROM (
4555
SELECT #{quoted_id_column_name} AS id, row_number() OVER(ORDER BY #{order_by}) AS seq
4656
FROM #{quoted_table_name}
47-
WHERE #{where_eq(parent_column_name, parent_id)} #{min_where}
57+
WHERE #{where_eq(parent_column_name, parent_id)} #{min_where} #{belong_to_scope}
4858
) AS t
4959
WHERE #{quoted_table_name}.#{quoted_id_column_name} = t.id and
5060
#{quoted_table_name}.#{quoted_order_column(false)} is distinct from t.seq + #{minimum_sort_order_value.to_i - 1}
@@ -57,14 +67,15 @@ def rows_updated(result)
5767
end
5868

5969
module GenericAdapter
60-
def reorder_with_parent_id(parent_id, minimum_sort_order_value = nil)
70+
def reorder_with_parent_id(parent_id:, minimum_sort_order_value: nil, belong_to_name: nil, belong_to_id: nil)
6171
return if parent_id.nil? && dont_order_roots
6272
scope = model_class.
6373
where(parent_column_sym => parent_id).
6474
order(nulls_last_order_by)
6575
if minimum_sort_order_value
6676
scope = scope.where("#{quoted_order_column} >= #{minimum_sort_order_value}")
6777
end
78+
scope = scope.where(belong_to_name => belong_to_id) if belong_to_id
6879
scope.each_with_index do |ea, idx|
6980
ea.update_order_value(idx + minimum_sort_order_value.to_i)
7081
end

lib/closure_tree/support_attributes.rb

+8
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ def parent_column_sym
3636
parent_column_name.to_sym
3737
end
3838

39+
def belong_to_column_name
40+
options[:order_belong_to]
41+
end
42+
43+
def belong_to_column_sym
44+
belong_to_column_name&.to_sym
45+
end
46+
3947
def name_column
4048
options[:name_column]
4149
end

spec/closure_tree/root_ordering.rb

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
5+
describe Block do
6+
describe "correct root order_value" do
7+
let!(:group) { Group.create!(name: "TheGroup") }
8+
let!(:user1) { User.create!(email: "[email protected]", group_id: group.id) }
9+
let!(:user2) { User.create!(email: "[email protected]", group_id: group.id) }
10+
let!(:block1) { Block.create!(name: "1block", user_id: user1.id) }
11+
let!(:block2) { Block.create!(name: "2block", user_id: user2.id) }
12+
let!(:block3) { Block.create!(name: "3block", user_id: user1.id) }
13+
let!(:block4) { Block.create!(name: "4block", user_id: user2.id) }
14+
let!(:block5) { Block.create!(name: "5block", user_id: user1.id) }
15+
let!(:block6) { Block.create!(name: "6block", user_id: user2.id) }
16+
17+
it "should set order_value on roots" do
18+
assert_equal block1.self_and_siblings.pluck(:sort_order), [1,2,3]
19+
assert_equal block2.self_and_siblings.pluck(:sort_order), [1,2,3]
20+
end
21+
end
22+
end

spec/support/models.rb

+7
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ class ContractType < ActiveRecord::Base
7878
has_many :contracts, inverse_of: :contract_type
7979
end
8080

81+
class Block < ApplicationRecord
82+
acts_as_tree order: :column_whereby_ordering_is_inferred, # <- symbol, and not "sort_order"
83+
numeric_order: true,
84+
dependent: :destroy,
85+
order_belong_to: :user_id
86+
end
87+
8188
class Label < ActiveRecord::Base
8289
# make sure order doesn't matter
8390
acts_as_tree :order => :column_whereby_ordering_is_inferred, # <- symbol, and not "sort_order"

spec/support/schema.rb

+8
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212

1313
add_foreign_key(:tags, :tags, :column => 'parent_id')
1414

15+
create_table 'blocks' do |t|
16+
t.string 'name'
17+
t.references 'parent'
18+
t.references 'user', null: false
19+
t.integer 'sort_order'
20+
t.timestamps null: false
21+
end
22+
1523
create_table "tag_hierarchies", :id => false do |t|
1624
t.references "ancestor", :null => false
1725
t.references "descendant", :null => false

0 commit comments

Comments
 (0)