closure_tree 6.5.0 → 7.4.0
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.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +98 -0
- data/.gitignore +2 -0
- data/.rspec +1 -1
- data/Appraisals +90 -7
- data/CHANGELOG.md +100 -42
- data/Gemfile +3 -11
- data/README.md +68 -24
- data/Rakefile +16 -10
- data/_config.yml +1 -0
- data/bin/appraisal +29 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/closure_tree.gemspec +16 -9
- data/lib/closure_tree/finders.rb +32 -9
- data/lib/closure_tree/has_closure_tree.rb +4 -0
- data/lib/closure_tree/has_closure_tree_root.rb +5 -7
- data/lib/closure_tree/hash_tree_support.rb +4 -4
- data/lib/closure_tree/hierarchy_maintenance.rb +28 -8
- data/lib/closure_tree/model.rb +42 -16
- data/lib/closure_tree/numeric_deterministic_ordering.rb +20 -6
- data/lib/closure_tree/numeric_order_support.rb +7 -3
- data/lib/closure_tree/support.rb +18 -12
- data/lib/closure_tree/support_attributes.rb +10 -1
- data/lib/closure_tree/support_flags.rb +1 -4
- data/lib/closure_tree/version.rb +1 -1
- data/lib/generators/closure_tree/migration_generator.rb +8 -0
- data/lib/generators/closure_tree/templates/create_hierarchies_table.rb.erb +1 -1
- metadata +78 -79
- data/.travis.yml +0 -29
- data/gemfiles/activerecord_4.2.gemfile +0 -19
- data/gemfiles/activerecord_5.0.gemfile +0 -19
- data/gemfiles/activerecord_5.0_foreigner.gemfile +0 -20
- data/gemfiles/activerecord_edge.gemfile +0 -20
- data/img/example.png +0 -0
- data/img/preorder.png +0 -0
- data/spec/cache_invalidation_spec.rb +0 -39
- data/spec/cuisine_type_spec.rb +0 -38
- data/spec/db/database.yml +0 -21
- data/spec/db/models.rb +0 -128
- data/spec/db/schema.rb +0 -166
- data/spec/fixtures/tags.yml +0 -98
- data/spec/generators/migration_generator_spec.rb +0 -48
- data/spec/has_closure_tree_root_spec.rb +0 -154
- data/spec/hierarchy_maintenance_spec.rb +0 -16
- data/spec/label_spec.rb +0 -554
- data/spec/matcher_spec.rb +0 -34
- data/spec/metal_spec.rb +0 -55
- data/spec/model_spec.rb +0 -9
- data/spec/namespace_type_spec.rb +0 -13
- data/spec/parallel_spec.rb +0 -159
- data/spec/spec_helper.rb +0 -24
- data/spec/support/database.rb +0 -52
- data/spec/support/database_cleaner.rb +0 -14
- data/spec/support/exceed_query_limit.rb +0 -18
- data/spec/support/hash_monkey_patch.rb +0 -13
- data/spec/support/query_counter.rb +0 -18
- data/spec/support/sqlite3_with_advisory_lock.rb +0 -10
- data/spec/support_spec.rb +0 -14
- data/spec/tag_examples.rb +0 -665
- data/spec/tag_spec.rb +0 -6
- data/spec/user_spec.rb +0 -174
- data/spec/uuid_tag_spec.rb +0 -6
@@ -20,7 +20,7 @@ module ClosureTree
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def _ct_validate
|
23
|
-
if
|
23
|
+
if !(defined? @_ct_skip_cycle_detection) &&
|
24
24
|
!new_record? && # don't validate for cycles if we're a new record
|
25
25
|
changes[_ct.parent_column_name] && # don't validate for cycles if we didn't change our parent
|
26
26
|
parent.present? && # don't validate if we're root
|
@@ -35,10 +35,13 @@ module ClosureTree
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def _ct_after_save
|
38
|
-
|
38
|
+
as_5_1 = ActiveSupport.version >= Gem::Version.new('5.1.0')
|
39
|
+
changes_method = as_5_1 ? :saved_changes : :changes
|
40
|
+
|
41
|
+
if public_send(changes_method)[_ct.parent_column_name] || @was_new_record
|
39
42
|
rebuild!
|
40
43
|
end
|
41
|
-
if
|
44
|
+
if public_send(changes_method)[_ct.parent_column_name] && !@was_new_record
|
42
45
|
# Resetting the ancestral collections addresses
|
43
46
|
# https://github.com/mceachen/closure_tree/issues/68
|
44
47
|
ancestor_hierarchies.reload
|
@@ -61,10 +64,10 @@ module ClosureTree
|
|
61
64
|
|
62
65
|
def rebuild!(called_by_rebuild = false)
|
63
66
|
_ct.with_advisory_lock do
|
64
|
-
delete_hierarchy_references unless @was_new_record
|
67
|
+
delete_hierarchy_references unless (defined? @was_new_record) && @was_new_record
|
65
68
|
hierarchy_class.create!(:ancestor => self, :descendant => self, :generations => 0)
|
66
69
|
unless root?
|
67
|
-
_ct.connection.execute <<-SQL.
|
70
|
+
_ct.connection.execute <<-SQL.squish
|
68
71
|
INSERT INTO #{_ct.quoted_hierarchy_table_name}
|
69
72
|
(ancestor_id, descendant_id, generations)
|
70
73
|
SELECT x.ancestor_id, #{_ct.quote(_ct_id)}, x.generations + 1
|
@@ -91,7 +94,7 @@ module ClosureTree
|
|
91
94
|
# It shouldn't affect performance of postgresql.
|
92
95
|
# See http://dev.mysql.com/doc/refman/5.0/en/subquery-errors.html
|
93
96
|
# Also: PostgreSQL doesn't support INNER JOIN on DELETE, so we can't use that.
|
94
|
-
_ct.connection.execute <<-SQL.
|
97
|
+
_ct.connection.execute <<-SQL.squish
|
95
98
|
DELETE FROM #{_ct.quoted_hierarchy_table_name}
|
96
99
|
WHERE descendant_id IN (
|
97
100
|
SELECT DISTINCT descendant_id
|
@@ -99,7 +102,7 @@ module ClosureTree
|
|
99
102
|
FROM #{_ct.quoted_hierarchy_table_name}
|
100
103
|
WHERE ancestor_id = #{_ct.quote(id)}
|
101
104
|
OR descendant_id = #{_ct.quote(id)}
|
102
|
-
)
|
105
|
+
) #{ _ct.t_alias_keyword } x )
|
103
106
|
SQL
|
104
107
|
end
|
105
108
|
end
|
@@ -109,11 +112,28 @@ module ClosureTree
|
|
109
112
|
# Note that the hierarchy table will be truncated.
|
110
113
|
def rebuild!
|
111
114
|
_ct.with_advisory_lock do
|
112
|
-
|
115
|
+
cleanup!
|
113
116
|
roots.find_each { |n| n.send(:rebuild!) } # roots just uses the parent_id column, so this is safe.
|
114
117
|
end
|
115
118
|
nil
|
116
119
|
end
|
120
|
+
|
121
|
+
def cleanup!
|
122
|
+
hierarchy_table = hierarchy_class.arel_table
|
123
|
+
|
124
|
+
[:descendant_id, :ancestor_id].each do |foreign_key|
|
125
|
+
alias_name = foreign_key.to_s.split('_').first + "s"
|
126
|
+
alias_table = Arel::Table.new(table_name).alias(alias_name)
|
127
|
+
arel_join = hierarchy_table.join(alias_table, Arel::Nodes::OuterJoin)
|
128
|
+
.on(alias_table[primary_key].eq(hierarchy_table[foreign_key]))
|
129
|
+
.join_sources
|
130
|
+
|
131
|
+
lonely_childs = hierarchy_class.joins(arel_join).where(alias_table[primary_key].eq(nil))
|
132
|
+
ids = lonely_childs.pluck(foreign_key)
|
133
|
+
|
134
|
+
hierarchy_class.where(hierarchy_table[foreign_key].in(ids)).delete_all
|
135
|
+
end
|
136
|
+
end
|
117
137
|
end
|
118
138
|
end
|
119
139
|
end
|
data/lib/closure_tree/model.rb
CHANGED
@@ -6,20 +6,20 @@ module ClosureTree
|
|
6
6
|
|
7
7
|
included do
|
8
8
|
|
9
|
-
belongs_to :parent, nil,
|
9
|
+
belongs_to :parent, nil, **_ct.belongs_to_with_optional_option(
|
10
10
|
class_name: _ct.model_class.to_s,
|
11
11
|
foreign_key: _ct.parent_column_name,
|
12
12
|
inverse_of: :children,
|
13
13
|
touch: _ct.options[:touch],
|
14
14
|
optional: true)
|
15
15
|
|
16
|
-
order_by_generations = "#{_ct.quoted_hierarchy_table_name}.generations
|
16
|
+
order_by_generations = -> { Arel.sql("#{_ct.quoted_hierarchy_table_name}.generations ASC") }
|
17
17
|
|
18
|
-
has_many :children, *_ct.
|
18
|
+
has_many :children, *_ct.has_many_order_with_option, **{
|
19
19
|
class_name: _ct.model_class.to_s,
|
20
20
|
foreign_key: _ct.parent_column_name,
|
21
21
|
dependent: _ct.options[:dependent],
|
22
|
-
inverse_of: :parent
|
22
|
+
inverse_of: :parent } do
|
23
23
|
# We have to redefine hash_tree because the activerecord relation is already scoped to parent_id.
|
24
24
|
def hash_tree(options = {})
|
25
25
|
# we want limit_depth + 1 because we don't do self_and_descendants.
|
@@ -28,25 +28,21 @@ module ClosureTree
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
has_many :ancestor_hierarchies, *_ct.
|
31
|
+
has_many :ancestor_hierarchies, *_ct.has_many_order_without_option(order_by_generations),
|
32
32
|
class_name: _ct.hierarchy_class_name,
|
33
|
-
foreign_key: 'descendant_id'
|
34
|
-
order: order_by_generations)
|
33
|
+
foreign_key: 'descendant_id'
|
35
34
|
|
36
|
-
has_many :self_and_ancestors, *_ct.
|
35
|
+
has_many :self_and_ancestors, *_ct.has_many_order_without_option(order_by_generations),
|
37
36
|
through: :ancestor_hierarchies,
|
38
|
-
source: :ancestor
|
39
|
-
order: order_by_generations)
|
37
|
+
source: :ancestor
|
40
38
|
|
41
|
-
has_many :descendant_hierarchies, *_ct.
|
39
|
+
has_many :descendant_hierarchies, *_ct.has_many_order_without_option(order_by_generations),
|
42
40
|
class_name: _ct.hierarchy_class_name,
|
43
|
-
foreign_key: 'ancestor_id'
|
44
|
-
order: order_by_generations)
|
41
|
+
foreign_key: 'ancestor_id'
|
45
42
|
|
46
|
-
has_many :self_and_descendants, *_ct.
|
43
|
+
has_many :self_and_descendants, *_ct.has_many_order_with_option(order_by_generations),
|
47
44
|
through: :descendant_hierarchies,
|
48
|
-
source: :descendant
|
49
|
-
order: order_by_generations)
|
45
|
+
source: :descendant
|
50
46
|
end
|
51
47
|
|
52
48
|
# Delegate to the Support instance on the class:
|
@@ -134,6 +130,36 @@ module ClosureTree
|
|
134
130
|
_ct.ids_from(siblings)
|
135
131
|
end
|
136
132
|
|
133
|
+
# node's parent is this record
|
134
|
+
def parent_of?(node)
|
135
|
+
self == node.parent
|
136
|
+
end
|
137
|
+
|
138
|
+
# node's root is this record
|
139
|
+
def root_of?(node)
|
140
|
+
self == node.root
|
141
|
+
end
|
142
|
+
|
143
|
+
# node's ancestors include this record
|
144
|
+
def ancestor_of?(node)
|
145
|
+
node.ancestors.include? self
|
146
|
+
end
|
147
|
+
|
148
|
+
# node is record's ancestor
|
149
|
+
def descendant_of?(node)
|
150
|
+
self.ancestors.include? node
|
151
|
+
end
|
152
|
+
|
153
|
+
# node is record's parent
|
154
|
+
def child_of?(node)
|
155
|
+
self.parent == node
|
156
|
+
end
|
157
|
+
|
158
|
+
# node and record have a same root
|
159
|
+
def family_of?(node)
|
160
|
+
self.root == node.root
|
161
|
+
end
|
162
|
+
|
137
163
|
# Alias for appending to the children collection.
|
138
164
|
# You can also add directly to the children collection, if you'd prefer.
|
139
165
|
def add_child(child_node)
|
@@ -10,8 +10,13 @@ module ClosureTree
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def _ct_reorder_prior_siblings_if_parent_changed
|
13
|
-
|
14
|
-
|
13
|
+
as_5_1 = ActiveSupport.version >= Gem::Version.new('5.1.0')
|
14
|
+
change_method = as_5_1 ? :saved_change_to_attribute? : :attribute_changed?
|
15
|
+
|
16
|
+
if public_send(change_method, _ct.parent_column_name) && !@was_new_record
|
17
|
+
attribute_method = as_5_1 ? :attribute_before_last_save : :attribute_was
|
18
|
+
|
19
|
+
was_parent_id = public_send(attribute_method, _ct.parent_column_name)
|
15
20
|
_ct.reorder_with_parent_id(was_parent_id)
|
16
21
|
end
|
17
22
|
end
|
@@ -46,7 +51,7 @@ module ClosureTree
|
|
46
51
|
|
47
52
|
# If node is nil, order the whole tree.
|
48
53
|
def _ct_sum_order_by(node = nil)
|
49
|
-
stats_sql = <<-SQL.
|
54
|
+
stats_sql = <<-SQL.squish
|
50
55
|
SELECT
|
51
56
|
count(*) as total_descendants,
|
52
57
|
max(generations) as max_depth
|
@@ -60,11 +65,16 @@ module ClosureTree
|
|
60
65
|
node_score = "(1 + anc.#{_ct.quoted_order_column(false)}) * " +
|
61
66
|
"power(#{h['total_descendants']}, #{h['max_depth'].to_i + 1} - #{depth_column})"
|
62
67
|
|
63
|
-
|
68
|
+
# We want the NULLs to be first in case we are not ordering roots and they have NULL order.
|
69
|
+
Arel.sql("SUM(#{node_score}) IS NULL DESC, SUM(#{node_score})")
|
64
70
|
end
|
65
71
|
|
66
72
|
def roots_and_descendants_preordered
|
67
|
-
|
73
|
+
if _ct.dont_order_roots
|
74
|
+
raise ClosureTree::RootOrderingDisabledError.new("Root ordering is disabled on this model")
|
75
|
+
end
|
76
|
+
|
77
|
+
join_sql = <<-SQL.squish
|
68
78
|
JOIN #{_ct.quoted_hierarchy_table_name} anc_hier
|
69
79
|
ON anc_hier.descendant_id = #{_ct.quoted_table_name}.#{_ct.quoted_id_column_name}
|
70
80
|
JOIN #{_ct.quoted_table_name} anc
|
@@ -73,7 +83,7 @@ module ClosureTree
|
|
73
83
|
SELECT descendant_id, max(generations) AS max_depth
|
74
84
|
FROM #{_ct.quoted_hierarchy_table_name}
|
75
85
|
GROUP BY descendant_id
|
76
|
-
)
|
86
|
+
) #{ _ct.t_alias_keyword } depths ON depths.descendant_id = anc.#{_ct.quoted_id_column_name}
|
77
87
|
SQL
|
78
88
|
joins(join_sql)
|
79
89
|
.group("#{_ct.quoted_table_name}.#{_ct.quoted_id_column_name}")
|
@@ -108,6 +118,10 @@ module ClosureTree
|
|
108
118
|
def add_sibling(sibling, add_after = true)
|
109
119
|
fail "can't add self as sibling" if self == sibling
|
110
120
|
|
121
|
+
if _ct.dont_order_roots && parent.nil?
|
122
|
+
raise ClosureTree::RootOrderingDisabledError.new("Root ordering is disabled on this model")
|
123
|
+
end
|
124
|
+
|
111
125
|
# Make sure self isn't dirty, because we're going to call reload:
|
112
126
|
save
|
113
127
|
|
@@ -14,13 +14,14 @@ module ClosureTree
|
|
14
14
|
|
15
15
|
module MysqlAdapter
|
16
16
|
def reorder_with_parent_id(parent_id, minimum_sort_order_value = nil)
|
17
|
+
return if parent_id.nil? && dont_order_roots
|
17
18
|
min_where = if minimum_sort_order_value
|
18
19
|
"AND #{quoted_order_column} >= #{minimum_sort_order_value}"
|
19
20
|
else
|
20
21
|
""
|
21
22
|
end
|
22
23
|
connection.execute 'SET @i = 0'
|
23
|
-
connection.execute <<-SQL.
|
24
|
+
connection.execute <<-SQL.squish
|
24
25
|
UPDATE #{quoted_table_name}
|
25
26
|
SET #{quoted_order_column} = (@i := @i + 1) + #{minimum_sort_order_value.to_i - 1}
|
26
27
|
WHERE #{where_eq(parent_column_name, parent_id)} #{min_where}
|
@@ -31,12 +32,13 @@ module ClosureTree
|
|
31
32
|
|
32
33
|
module PostgreSQLAdapter
|
33
34
|
def reorder_with_parent_id(parent_id, minimum_sort_order_value = nil)
|
35
|
+
return if parent_id.nil? && dont_order_roots
|
34
36
|
min_where = if minimum_sort_order_value
|
35
37
|
"AND #{quoted_order_column} >= #{minimum_sort_order_value}"
|
36
38
|
else
|
37
39
|
""
|
38
40
|
end
|
39
|
-
connection.execute <<-SQL.
|
41
|
+
connection.execute <<-SQL.squish
|
40
42
|
UPDATE #{quoted_table_name}
|
41
43
|
SET #{quoted_order_column(false)} = t.seq + #{minimum_sort_order_value.to_i - 1}
|
42
44
|
FROM (
|
@@ -44,7 +46,8 @@ module ClosureTree
|
|
44
46
|
FROM #{quoted_table_name}
|
45
47
|
WHERE #{where_eq(parent_column_name, parent_id)} #{min_where}
|
46
48
|
) AS t
|
47
|
-
WHERE #{quoted_table_name}.#{quoted_id_column_name} = t.id
|
49
|
+
WHERE #{quoted_table_name}.#{quoted_id_column_name} = t.id and
|
50
|
+
#{quoted_table_name}.#{quoted_order_column(false)} is distinct from t.seq + #{minimum_sort_order_value.to_i - 1}
|
48
51
|
SQL
|
49
52
|
end
|
50
53
|
|
@@ -55,6 +58,7 @@ module ClosureTree
|
|
55
58
|
|
56
59
|
module GenericAdapter
|
57
60
|
def reorder_with_parent_id(parent_id, minimum_sort_order_value = nil)
|
61
|
+
return if parent_id.nil? && dont_order_roots
|
58
62
|
scope = model_class.
|
59
63
|
where(parent_column_sym => parent_id).
|
60
64
|
order(nulls_last_order_by)
|
data/lib/closure_tree/support.rb
CHANGED
@@ -22,7 +22,8 @@ module ClosureTree
|
|
22
22
|
:parent_column_name => 'parent_id',
|
23
23
|
:dependent => :nullify, # or :destroy or :delete_all -- see the README
|
24
24
|
:name_column => 'name',
|
25
|
-
:with_advisory_lock => true
|
25
|
+
:with_advisory_lock => true,
|
26
|
+
:numeric_order => false
|
26
27
|
}.merge(options)
|
27
28
|
raise ArgumentError, "name_column can't be 'path'" if options[:name_column] == 'path'
|
28
29
|
if order_is_numeric?
|
@@ -31,13 +32,15 @@ module ClosureTree
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def hierarchy_class_for_model
|
34
|
-
|
35
|
+
parent_class = ActiveSupport::VERSION::MAJOR >= 6 ? model_class.module_parent : model_class.parent
|
36
|
+
hierarchy_class = parent_class.const_set(short_hierarchy_class_name, Class.new(model_class.superclass))
|
35
37
|
use_attr_accessible = use_attr_accessible?
|
36
38
|
include_forbidden_attributes_protection = include_forbidden_attributes_protection?
|
37
|
-
|
39
|
+
model_class_name = model_class.to_s
|
40
|
+
hierarchy_class.class_eval do
|
38
41
|
include ActiveModel::ForbiddenAttributesProtection if include_forbidden_attributes_protection
|
39
|
-
belongs_to :ancestor, :
|
40
|
-
belongs_to :descendant, :
|
42
|
+
belongs_to :ancestor, class_name: model_class_name
|
43
|
+
belongs_to :descendant, class_name: model_class_name
|
41
44
|
attr_accessible :ancestor, :descendant, :generations if use_attr_accessible
|
42
45
|
def ==(other)
|
43
46
|
self.class == other.class && ancestor_id == other.ancestor_id && descendant_id == other.descendant_id
|
@@ -46,7 +49,7 @@ module ClosureTree
|
|
46
49
|
def hash
|
47
50
|
ancestor_id.hash << 31 ^ descendant_id.hash
|
48
51
|
end
|
49
|
-
|
52
|
+
end
|
50
53
|
hierarchy_class.table_name = hierarchy_table_name
|
51
54
|
hierarchy_class
|
52
55
|
end
|
@@ -77,17 +80,20 @@ module ClosureTree
|
|
77
80
|
end
|
78
81
|
|
79
82
|
def belongs_to_with_optional_option(opts)
|
80
|
-
|
83
|
+
ActiveRecord::VERSION::MAJOR < 5 ? opts.except(:optional) : opts
|
81
84
|
end
|
82
85
|
|
83
86
|
# lambda-ize the order, but don't apply the default order_option
|
84
|
-
def
|
85
|
-
|
87
|
+
def has_many_order_without_option(order_by_opt)
|
88
|
+
[lambda { order(order_by_opt.call) }]
|
86
89
|
end
|
87
90
|
|
88
|
-
def
|
89
|
-
order_options = [
|
90
|
-
[lambda {
|
91
|
+
def has_many_order_with_option(order_by_opt=nil)
|
92
|
+
order_options = [order_by_opt, order_by].compact
|
93
|
+
[lambda {
|
94
|
+
order_options = order_options.map { |o| o.is_a?(Proc) ? o.call : o }
|
95
|
+
order(order_options)
|
96
|
+
}]
|
91
97
|
end
|
92
98
|
|
93
99
|
def ids_from(scope)
|
@@ -75,8 +75,12 @@ module ClosureTree
|
|
75
75
|
options[:order]
|
76
76
|
end
|
77
77
|
|
78
|
+
def dont_order_roots
|
79
|
+
options[:dont_order_roots] || false
|
80
|
+
end
|
81
|
+
|
78
82
|
def nulls_last_order_by
|
79
|
-
"-#{quoted_order_column} #{order_by_order(
|
83
|
+
Arel.sql "-#{quoted_order_column} #{order_by_order(true)}"
|
80
84
|
end
|
81
85
|
|
82
86
|
def order_by_order(reverse = false)
|
@@ -110,5 +114,10 @@ module ClosureTree
|
|
110
114
|
prefix = include_table_name ? "#{quoted_table_name}." : ""
|
111
115
|
"#{prefix}#{connection.quote_column_name(order_column)}"
|
112
116
|
end
|
117
|
+
|
118
|
+
# table_name alias keyword , like "AS". When used on table name alias, Oracle Database don't support used 'AS'
|
119
|
+
def t_alias_keyword
|
120
|
+
(ActiveRecord::Base.connection.adapter_name.to_sym == :OracleEnhanced) ? "" : "AS"
|
121
|
+
end
|
113
122
|
end
|
114
123
|
end
|
@@ -17,10 +17,7 @@ module ClosureTree
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def order_is_numeric?
|
20
|
-
|
21
|
-
return false if !order_option? || !model_class.table_exists?
|
22
|
-
c = model_class.columns_hash[order_column]
|
23
|
-
c && c.type == :integer
|
20
|
+
options[:numeric_order]
|
24
21
|
end
|
25
22
|
|
26
23
|
def subclass?
|
data/lib/closure_tree/version.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'closure_tree/active_record_support'
|
2
2
|
require 'forwardable'
|
3
|
+
require 'rails/generators'
|
3
4
|
require 'rails/generators/active_record'
|
4
5
|
require 'rails/generators/named_base'
|
5
6
|
|
@@ -41,6 +42,13 @@ module ClosureTree
|
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
45
|
+
def migration_version
|
46
|
+
major = ActiveRecord::VERSION::MAJOR
|
47
|
+
if major >= 5
|
48
|
+
"[#{major}.#{ActiveRecord::VERSION::MINOR}]"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
44
52
|
def self.next_migration_number(dirname)
|
45
53
|
ActiveRecord::Generators::Base.next_migration_number(dirname)
|
46
54
|
end
|