ransack 2.1.1 → 2.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/cronjob.yml +105 -0
- data/.github/workflows/rubocop.yml +20 -0
- data/.github/workflows/test.yml +154 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +44 -0
- data/CHANGELOG.md +55 -1
- data/CONTRIBUTING.md +13 -11
- data/Gemfile +23 -17
- data/README.md +119 -52
- data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +78 -0
- data/bug_report_templates/test-ransacker-arel-present-predicate.rb +71 -0
- data/docs/img/create_release.png +0 -0
- data/docs/release_process.md +20 -0
- data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_association.rb +2 -9
- data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_dependency.rb +25 -3
- data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +11 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +80 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +74 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +93 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_6.2_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_6.2_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_6.2_ruby_2/reflection.rb +1 -0
- data/lib/{polyamorous.rb → polyamorous/polyamorous.rb} +4 -5
- data/lib/ransack.rb +3 -3
- data/lib/ransack/adapters/active_record/base.rb +4 -0
- data/lib/ransack/adapters/active_record/context.rb +67 -68
- data/lib/ransack/adapters/active_record/ransack/constants.rb +18 -3
- data/lib/ransack/adapters/active_record/ransack/context.rb +2 -6
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +12 -5
- data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -1
- data/lib/ransack/configuration.rb +17 -1
- data/lib/ransack/constants.rb +3 -5
- data/lib/ransack/context.rb +19 -18
- data/lib/ransack/helpers.rb +1 -1
- data/lib/ransack/helpers/form_builder.rb +8 -14
- data/lib/ransack/helpers/form_helper.rb +1 -1
- data/lib/ransack/locale/az.yml +1 -1
- data/lib/ransack/locale/ca.yml +70 -0
- data/lib/ransack/locale/es.yml +22 -22
- data/lib/ransack/locale/fa.yml +70 -0
- data/lib/ransack/locale/fi.yml +71 -0
- data/lib/ransack/locale/sk.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +1 -1
- data/lib/ransack/nodes/condition.rb +7 -1
- data/lib/ransack/nodes/grouping.rb +1 -1
- data/lib/ransack/nodes/sort.rb +1 -1
- data/lib/ransack/nodes/value.rb +1 -1
- data/lib/ransack/predicate.rb +2 -1
- data/lib/ransack/search.rb +3 -1
- data/lib/ransack/translate.rb +115 -115
- data/lib/ransack/version.rb +1 -1
- data/ransack.gemspec +8 -23
- data/spec/blueprints/articles.rb +1 -1
- data/spec/blueprints/comments.rb +1 -1
- data/spec/blueprints/notes.rb +1 -1
- data/spec/blueprints/tags.rb +1 -1
- data/spec/console.rb +5 -5
- data/spec/helpers/polyamorous_helper.rb +3 -8
- data/spec/helpers/ransack_helper.rb +1 -1
- data/spec/{ransack → polyamorous}/join_association_spec.rb +7 -0
- data/spec/{ransack → polyamorous}/join_dependency_spec.rb +18 -7
- data/spec/{ransack → polyamorous}/join_spec.rb +0 -0
- data/spec/ransack/adapters/active_record/base_spec.rb +9 -6
- data/spec/ransack/adapters/active_record/context_spec.rb +60 -18
- data/spec/ransack/configuration_spec.rb +10 -0
- data/spec/ransack/helpers/form_helper_spec.rb +16 -16
- data/spec/ransack/nodes/grouping_spec.rb +2 -2
- data/spec/ransack/predicate_spec.rb +54 -2
- data/spec/ransack/search_spec.rb +127 -15
- data/spec/spec_helper.rb +10 -5
- data/spec/support/schema.rb +14 -3
- metadata +41 -137
- data/.travis.yml +0 -37
- data/lib/polyamorous/activerecord_5.0_ruby_2/join_association.rb +0 -2
- data/lib/polyamorous/activerecord_5.0_ruby_2/join_dependency.rb +0 -2
- data/lib/polyamorous/activerecord_5.1_ruby_2/join_association.rb +0 -32
- data/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +0 -112
- data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_association.rb +0 -32
- data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_dependency.rb +0 -113
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
## Release Process
|
2
|
+
|
3
|
+
*For maintainers of Ransack.*
|
4
|
+
|
5
|
+
To release a new version of Ransack and publish it to RubyGems, take the following steps:
|
6
|
+
|
7
|
+
- Create a new release, marked `Prerelease`.
|
8
|
+
<<<<<<< Updated upstream
|
9
|
+
- Update the versions file to the new release, commit and push to `master`.
|
10
|
+
=======
|
11
|
+
- Update the [version.rb](../lib/ransack/version.rb) file to the new release, commit and push to `master`.
|
12
|
+
>>>>>>> Stashed changes
|
13
|
+
- From the terminal, run the following commands
|
14
|
+
|
15
|
+
```bash
|
16
|
+
rake build
|
17
|
+
rake release
|
18
|
+
```
|
19
|
+
|
20
|
+
![Create a Release](img/create_release.png)
|
data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_association.rb
RENAMED
@@ -1,5 +1,3 @@
|
|
1
|
-
# active_record_5.2.1_ruby_2/join_association.rb
|
2
|
-
|
3
1
|
module Polyamorous
|
4
2
|
module JoinAssociationExtensions
|
5
3
|
include SwappingReflectionClass
|
@@ -19,13 +17,8 @@ module Polyamorous
|
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
22
|
-
def
|
23
|
-
|
24
|
-
super(klass, table, key, foreign_table, foreign_key)
|
25
|
-
.and(foreign_table[reflection.foreign_type].eq(reflection.klass.name))
|
26
|
-
else
|
27
|
-
super(klass, table, key, foreign_table, foreign_key)
|
28
|
-
end
|
20
|
+
def ==(other)
|
21
|
+
base_klass == other.base_klass
|
29
22
|
end
|
30
23
|
end
|
31
24
|
end
|
data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_dependency.rb
RENAMED
@@ -1,9 +1,6 @@
|
|
1
|
-
# active_record_5.2.1_ruby_2/join_dependency.rb
|
2
|
-
|
3
1
|
module Polyamorous
|
4
2
|
module JoinDependencyExtensions
|
5
3
|
# Replaces ActiveRecord::Associations::JoinDependency#build
|
6
|
-
#
|
7
4
|
def build(associations, base_klass)
|
8
5
|
associations.map do |name, right|
|
9
6
|
if name.is_a? Join
|
@@ -30,6 +27,31 @@ module Polyamorous
|
|
30
27
|
end
|
31
28
|
end
|
32
29
|
|
30
|
+
def join_constraints(joins_to_add, join_type, alias_tracker)
|
31
|
+
@alias_tracker = alias_tracker
|
32
|
+
|
33
|
+
construct_tables!(join_root)
|
34
|
+
joins = make_join_constraints(join_root, join_type)
|
35
|
+
|
36
|
+
joins.concat joins_to_add.flat_map { |oj|
|
37
|
+
construct_tables!(oj.join_root)
|
38
|
+
if join_root.match?(oj.join_root) && join_root.table.name == oj.join_root.table.name
|
39
|
+
walk join_root, oj.join_root
|
40
|
+
else
|
41
|
+
make_join_constraints(oj.join_root, join_type)
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
def make_constraints(parent, child, join_type = Arel::Nodes::OuterJoin)
|
48
|
+
foreign_table = parent.table
|
49
|
+
foreign_klass = parent.base_klass
|
50
|
+
join_type = child.join_type || join_type if join_type == Arel::Nodes::InnerJoin
|
51
|
+
joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
52
|
+
joins.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
|
53
|
+
end
|
54
|
+
|
33
55
|
module ClassMethods
|
34
56
|
# Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
|
35
57
|
#
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'polyamorous/activerecord_5.2_ruby_2/join_association'
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# active_record_6.0_ruby_2/join_dependency.rb
|
2
|
+
module Polyamorous
|
3
|
+
module JoinDependencyExtensions
|
4
|
+
# Replaces ActiveRecord::Associations::JoinDependency#build
|
5
|
+
def build(associations, base_klass)
|
6
|
+
associations.map do |name, right|
|
7
|
+
if name.is_a? Join
|
8
|
+
reflection = find_reflection base_klass, name.name
|
9
|
+
reflection.check_validity!
|
10
|
+
reflection.check_eager_loadable!
|
11
|
+
|
12
|
+
klass = if reflection.polymorphic?
|
13
|
+
name.klass || base_klass
|
14
|
+
else
|
15
|
+
reflection.klass
|
16
|
+
end
|
17
|
+
JoinAssociation.new(reflection, build(right, klass), name.klass, name.type)
|
18
|
+
else
|
19
|
+
reflection = find_reflection base_klass, name
|
20
|
+
reflection.check_validity!
|
21
|
+
reflection.check_eager_loadable!
|
22
|
+
|
23
|
+
if reflection.polymorphic?
|
24
|
+
raise ActiveRecord::EagerLoadPolymorphicError.new(reflection)
|
25
|
+
end
|
26
|
+
JoinAssociation.new(reflection, build(right, reflection.klass))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def join_constraints(joins_to_add, alias_tracker)
|
32
|
+
@alias_tracker = alias_tracker
|
33
|
+
|
34
|
+
construct_tables!(join_root)
|
35
|
+
joins = make_join_constraints(join_root, join_type)
|
36
|
+
|
37
|
+
joins.concat joins_to_add.flat_map { |oj|
|
38
|
+
construct_tables!(oj.join_root)
|
39
|
+
if join_root.match?(oj.join_root) && join_root.table.name == oj.join_root.table.name
|
40
|
+
walk join_root, oj.join_root, oj.join_type
|
41
|
+
else
|
42
|
+
make_join_constraints(oj.join_root, oj.join_type)
|
43
|
+
end
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def make_constraints(parent, child, join_type = Arel::Nodes::OuterJoin)
|
49
|
+
foreign_table = parent.table
|
50
|
+
foreign_klass = parent.base_klass
|
51
|
+
join_type = child.join_type || join_type if join_type == Arel::Nodes::InnerJoin
|
52
|
+
joins = child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker)
|
53
|
+
joins.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
|
54
|
+
end
|
55
|
+
|
56
|
+
module ClassMethods
|
57
|
+
# Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
|
58
|
+
#
|
59
|
+
def walk_tree(associations, hash)
|
60
|
+
case associations
|
61
|
+
when TreeNode
|
62
|
+
associations.add_to_tree(hash)
|
63
|
+
when Hash
|
64
|
+
associations.each do |k, v|
|
65
|
+
cache =
|
66
|
+
if TreeNode === k
|
67
|
+
k.add_to_tree(hash)
|
68
|
+
else
|
69
|
+
hash[k] ||= {}
|
70
|
+
end
|
71
|
+
walk_tree(v, cache)
|
72
|
+
end
|
73
|
+
else
|
74
|
+
super(associations, hash)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'polyamorous/activerecord_5.2_ruby_2/reflection'
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Polyamorous
|
2
|
+
module JoinAssociationExtensions
|
3
|
+
include SwappingReflectionClass
|
4
|
+
def self.prepended(base)
|
5
|
+
base.class_eval { attr_reader :join_type }
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(reflection, children, polymorphic_class = nil, join_type = Arel::Nodes::InnerJoin)
|
9
|
+
@join_type = join_type
|
10
|
+
if polymorphic_class && ::ActiveRecord::Base > polymorphic_class
|
11
|
+
swapping_reflection_klass(reflection, polymorphic_class) do |reflection|
|
12
|
+
super(reflection, children)
|
13
|
+
self.reflection.options[:polymorphic] = true
|
14
|
+
end
|
15
|
+
else
|
16
|
+
super(reflection, children)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Same as #join_constraints, but instead of constructing tables from the
|
21
|
+
# given block, uses the ones passed
|
22
|
+
def join_constraints_with_tables(foreign_table, foreign_klass, join_type, alias_tracker, tables)
|
23
|
+
joins = []
|
24
|
+
chain = []
|
25
|
+
|
26
|
+
reflection.chain.each.with_index do |reflection, i|
|
27
|
+
table = tables[i]
|
28
|
+
|
29
|
+
@table ||= table
|
30
|
+
chain << [reflection, table]
|
31
|
+
end
|
32
|
+
|
33
|
+
# The chain starts with the target table, but we want to end with it here (makes
|
34
|
+
# more sense in this context), so we reverse
|
35
|
+
chain.reverse_each do |reflection, table|
|
36
|
+
klass = reflection.klass
|
37
|
+
|
38
|
+
join_scope = reflection.join_scope(table, foreign_table, foreign_klass)
|
39
|
+
|
40
|
+
unless join_scope.references_values.empty?
|
41
|
+
join_dependency = join_scope.construct_join_dependency(
|
42
|
+
join_scope.eager_load_values | join_scope.includes_values, Arel::Nodes::OuterJoin
|
43
|
+
)
|
44
|
+
join_scope.joins!(join_dependency)
|
45
|
+
end
|
46
|
+
|
47
|
+
arel = join_scope.arel(alias_tracker.aliases)
|
48
|
+
nodes = arel.constraints.first
|
49
|
+
|
50
|
+
if nodes.is_a?(Arel::Nodes::And)
|
51
|
+
others = nodes.children.extract! do |node|
|
52
|
+
!Arel.fetch_attribute(node) { |attr| attr.relation.name == table.name }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
joins << table.create_join(table, table.create_on(nodes), join_type)
|
57
|
+
|
58
|
+
if others && !others.empty?
|
59
|
+
joins.concat arel.join_sources
|
60
|
+
append_constraints(joins.last, others)
|
61
|
+
end
|
62
|
+
|
63
|
+
# The current table in this iteration becomes the foreign table in the next
|
64
|
+
foreign_table, foreign_klass = table, klass
|
65
|
+
end
|
66
|
+
|
67
|
+
joins
|
68
|
+
end
|
69
|
+
|
70
|
+
def ==(other)
|
71
|
+
base_klass == other.base_klass
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# active_record_6.1_ruby_2/join_dependency.rb
|
2
|
+
module Polyamorous
|
3
|
+
module JoinDependencyExtensions
|
4
|
+
# Replaces ActiveRecord::Associations::JoinDependency#build
|
5
|
+
def build(associations, base_klass)
|
6
|
+
associations.map do |name, right|
|
7
|
+
if name.is_a? Join
|
8
|
+
reflection = find_reflection base_klass, name.name
|
9
|
+
reflection.check_validity!
|
10
|
+
reflection.check_eager_loadable!
|
11
|
+
|
12
|
+
klass = if reflection.polymorphic?
|
13
|
+
name.klass || base_klass
|
14
|
+
else
|
15
|
+
reflection.klass
|
16
|
+
end
|
17
|
+
JoinAssociation.new(reflection, build(right, klass), name.klass, name.type)
|
18
|
+
else
|
19
|
+
reflection = find_reflection base_klass, name
|
20
|
+
reflection.check_validity!
|
21
|
+
reflection.check_eager_loadable!
|
22
|
+
|
23
|
+
if reflection.polymorphic?
|
24
|
+
raise ActiveRecord::EagerLoadPolymorphicError.new(reflection)
|
25
|
+
end
|
26
|
+
JoinAssociation.new(reflection, build(right, reflection.klass))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def join_constraints(joins_to_add, alias_tracker, references)
|
32
|
+
@alias_tracker = alias_tracker
|
33
|
+
@joined_tables = {}
|
34
|
+
@references = {}
|
35
|
+
|
36
|
+
references.each do |table_name|
|
37
|
+
@references[table_name.to_sym] = table_name if table_name.is_a?(String)
|
38
|
+
end
|
39
|
+
|
40
|
+
joins = make_join_constraints(join_root, join_type)
|
41
|
+
|
42
|
+
joins.concat joins_to_add.flat_map { |oj|
|
43
|
+
if join_root.match?(oj.join_root) && join_root.table.name == oj.join_root.table.name
|
44
|
+
walk join_root, oj.join_root, oj.join_type
|
45
|
+
else
|
46
|
+
make_join_constraints(oj.join_root, oj.join_type)
|
47
|
+
end
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def construct_tables_for_association!(join_root, association)
|
52
|
+
tables = table_aliases_for(join_root, association)
|
53
|
+
association.table = tables.first
|
54
|
+
tables
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def table_aliases_for(parent, node)
|
60
|
+
node.reflection.chain.map { |reflection|
|
61
|
+
alias_tracker.aliased_table_for(reflection.klass.arel_table) do
|
62
|
+
root = reflection == node.reflection
|
63
|
+
name = reflection.alias_candidate(parent.table_name)
|
64
|
+
root ? name : "#{name}_join"
|
65
|
+
end
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
module ClassMethods
|
70
|
+
# Prepended before ActiveRecord::Associations::JoinDependency#walk_tree
|
71
|
+
#
|
72
|
+
def walk_tree(associations, hash)
|
73
|
+
case associations
|
74
|
+
when TreeNode
|
75
|
+
associations.add_to_tree(hash)
|
76
|
+
when Hash
|
77
|
+
associations.each do |k, v|
|
78
|
+
cache =
|
79
|
+
if TreeNode === k
|
80
|
+
k.add_to_tree(hash)
|
81
|
+
else
|
82
|
+
hash[k] ||= {}
|
83
|
+
end
|
84
|
+
walk_tree(v, cache)
|
85
|
+
end
|
86
|
+
else
|
87
|
+
super(associations, hash)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'polyamorous/activerecord_6.0_ruby_2/reflection'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'polyamorous/activerecord_6.1_ruby_2/join_association'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'polyamorous/activerecord_6.1_ruby_2/join_dependency'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'polyamorous/activerecord_6.1_ruby_2/reflection'
|
@@ -11,14 +11,13 @@ if defined?(::ActiveRecord)
|
|
11
11
|
require 'polyamorous/join'
|
12
12
|
require 'polyamorous/swapping_reflection_class'
|
13
13
|
|
14
|
-
ar_version = ::ActiveRecord::VERSION::STRING[0,3]
|
15
|
-
|
16
|
-
ar_version = "5.2.1" if ::ActiveRecord::VERSION::STRING >= "5.2.1"
|
17
|
-
|
18
|
-
%w(join_association join_dependency).each do |file|
|
14
|
+
ar_version = ::ActiveRecord::VERSION::STRING[0, 3]
|
15
|
+
%w(join_association join_dependency reflection).each do |file|
|
19
16
|
require "polyamorous/activerecord_#{ar_version}_ruby_2/#{file}"
|
20
17
|
end
|
21
18
|
|
19
|
+
ActiveRecord::Reflection::AbstractReflection.send(:prepend, Polyamorous::ReflectionExtensions)
|
20
|
+
|
22
21
|
Polyamorous::JoinDependency.send(:prepend, Polyamorous::JoinDependencyExtensions)
|
23
22
|
Polyamorous::JoinDependency.singleton_class.send(:prepend, Polyamorous::JoinDependencyExtensions::ClassMethods)
|
24
23
|
Polyamorous::JoinAssociation.send(:prepend, Polyamorous::JoinAssociationExtensions)
|
data/lib/ransack.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'active_support/core_ext'
|
2
2
|
require 'ransack/configuration'
|
3
3
|
require 'ransack/adapters'
|
4
|
+
require 'polyamorous/polyamorous'
|
4
5
|
|
5
6
|
Ransack::Adapters.object_mapper.require_constants
|
6
7
|
|
7
8
|
module Ransack
|
8
9
|
extend Configuration
|
9
|
-
class UntraversableAssociationError < StandardError; end
|
10
|
+
class UntraversableAssociationError < StandardError; end
|
10
11
|
end
|
11
12
|
|
12
13
|
Ransack.configure do |config|
|
@@ -20,12 +21,11 @@ end
|
|
20
21
|
|
21
22
|
require 'ransack/search'
|
22
23
|
require 'ransack/ransacker'
|
23
|
-
require 'ransack/helpers'
|
24
|
-
require 'action_controller'
|
25
24
|
require 'ransack/translate'
|
26
25
|
|
27
26
|
Ransack::Adapters.object_mapper.require_adapter
|
28
27
|
|
29
28
|
ActiveSupport.on_load(:action_controller) do
|
29
|
+
require 'ransack/helpers'
|
30
30
|
ActionController::Base.helper Ransack::Helpers::FormHelper
|
31
31
|
end
|
@@ -18,6 +18,10 @@ module Ransack
|
|
18
18
|
Search.new(self, params, options)
|
19
19
|
end
|
20
20
|
|
21
|
+
def ransack!(params = {}, options = {})
|
22
|
+
ransack(params, options.merge(ignore_unknown_conditions: false))
|
23
|
+
end
|
24
|
+
|
21
25
|
def ransacker(name, opts = {}, &block)
|
22
26
|
self._ransackers = _ransackers.merge name.to_s => Ransacker
|
23
27
|
.new(self, name, opts, &block)
|
@@ -1,18 +1,11 @@
|
|
1
1
|
require 'ransack/context'
|
2
|
-
require 'polyamorous'
|
2
|
+
require 'polyamorous/polyamorous'
|
3
3
|
|
4
4
|
module Ransack
|
5
5
|
module Adapters
|
6
6
|
module ActiveRecord
|
7
7
|
class Context < ::Ransack::Context
|
8
8
|
|
9
|
-
def initialize(object, options = {})
|
10
|
-
super
|
11
|
-
if ::ActiveRecord::VERSION::STRING < Constants::RAILS_5_2
|
12
|
-
@arel_visitor = @engine.connection.visitor
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
9
|
def relation_for(object)
|
17
10
|
object.all
|
18
11
|
end
|
@@ -49,6 +42,13 @@ module Ransack
|
|
49
42
|
if scope_or_sort.is_a?(Symbol)
|
50
43
|
relation = relation.send(scope_or_sort)
|
51
44
|
else
|
45
|
+
case Ransack.options[:postgres_fields_sort_option]
|
46
|
+
when :nulls_first
|
47
|
+
scope_or_sort = scope_or_sort.direction == :asc ? "#{scope_or_sort.to_sql} NULLS FIRST" : "#{scope_or_sort.to_sql} NULLS LAST"
|
48
|
+
when :nulls_last
|
49
|
+
scope_or_sort = scope_or_sort.direction == :asc ? "#{scope_or_sort.to_sql} NULLS LAST" : "#{scope_or_sort.to_sql} NULLS FIRST"
|
50
|
+
end
|
51
|
+
|
52
52
|
relation = relation.order(scope_or_sort)
|
53
53
|
end
|
54
54
|
end
|
@@ -104,20 +104,21 @@ module Ransack
|
|
104
104
|
# JoinDependency to track table aliases.
|
105
105
|
#
|
106
106
|
def join_sources
|
107
|
-
base, joins =
|
108
|
-
if ::ActiveRecord::VERSION::STRING > Constants::RAILS_5_2_0
|
107
|
+
base, joins = begin
|
109
108
|
alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(self.klass.connection, @object.table.name, [])
|
110
|
-
|
111
|
-
|
109
|
+
constraints = if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_1)
|
110
|
+
@join_dependency.join_constraints(@object.joins_values, alias_tracker, @object.references_values)
|
111
|
+
elsif ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_0)
|
112
|
+
@join_dependency.join_constraints(@object.joins_values, alias_tracker)
|
113
|
+
else
|
112
114
|
@join_dependency.join_constraints(@object.joins_values, @join_type, alias_tracker)
|
113
|
-
|
114
|
-
|
115
|
+
end
|
116
|
+
|
115
117
|
[
|
116
118
|
Arel::SelectManager.new(@object.table),
|
117
|
-
|
119
|
+
constraints
|
118
120
|
]
|
119
121
|
end
|
120
|
-
joins = joins.collect(&:joins).flatten if ::ActiveRecord::VERSION::STRING < Constants::RAILS_5_2
|
121
122
|
joins.each do |aliased_join|
|
122
123
|
base.from(aliased_join)
|
123
124
|
end
|
@@ -163,7 +164,7 @@ module Ransack
|
|
163
164
|
def build_correlated_subquery(association)
|
164
165
|
join_constraints = extract_joins(association)
|
165
166
|
join_root = join_constraints.shift
|
166
|
-
correlated_key = join_root
|
167
|
+
correlated_key = extract_correlated_key(join_root)
|
167
168
|
subquery = Arel::SelectManager.new(association.base_klass)
|
168
169
|
subquery.from(join_root.left)
|
169
170
|
subquery.project(correlated_key)
|
@@ -179,6 +180,35 @@ module Ransack
|
|
179
180
|
|
180
181
|
private
|
181
182
|
|
183
|
+
def extract_correlated_key(join_root)
|
184
|
+
case join_root
|
185
|
+
when Arel::Nodes::OuterJoin
|
186
|
+
# one of join_root.right/join_root.left is expected to be Arel::Nodes::On
|
187
|
+
if join_root.right.is_a?(Arel::Nodes::On)
|
188
|
+
extract_correlated_key(join_root.right.expr)
|
189
|
+
elsif join_root.left.is_a?(Arel::Nodes::On)
|
190
|
+
extract_correlated_key(join_root.left.expr)
|
191
|
+
else
|
192
|
+
raise 'Ransack encountered an unexpected arel structure'
|
193
|
+
end
|
194
|
+
when Arel::Nodes::Equality
|
195
|
+
pk = primary_key
|
196
|
+
if join_root.left == pk
|
197
|
+
join_root.right
|
198
|
+
elsif join_root.right == pk
|
199
|
+
join_root.left
|
200
|
+
else
|
201
|
+
nil
|
202
|
+
end
|
203
|
+
when Arel::Nodes::And
|
204
|
+
extract_correlated_key(join_root.left) || extract_correlated_key(join_root.right)
|
205
|
+
else
|
206
|
+
# eg parent was Arel::Nodes::And and the evaluated side was one of
|
207
|
+
# Arel::Nodes::Grouping or MultiTenant::TenantEnforcementClause
|
208
|
+
nil
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
182
212
|
def get_parent_and_attribute_name(str, parent = @base)
|
183
213
|
attr_name = nil
|
184
214
|
|
@@ -248,24 +278,15 @@ module Ransack
|
|
248
278
|
|
249
279
|
join_list = join_nodes + convert_join_strings_to_ast(relation.table, string_joins)
|
250
280
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
join_dependency.send(:alias_tracker).aliases[join.left.name.downcase] = 1
|
255
|
-
end
|
256
|
-
elsif ::ActiveRecord::VERSION::STRING == Constants::RAILS_5_2_0
|
257
|
-
alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(self.klass.connection, relation.table.name, join_list)
|
258
|
-
join_dependency = Polyamorous::JoinDependency.new(relation.klass, relation.table, association_joins, alias_tracker)
|
259
|
-
join_nodes.each do |join|
|
260
|
-
join_dependency.send(:alias_tracker).aliases[join.left.name.downcase] = 1
|
261
|
-
end
|
281
|
+
alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(self.klass.connection, relation.table.name, join_list)
|
282
|
+
join_dependency = if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_0)
|
283
|
+
Polyamorous::JoinDependency.new(relation.klass, relation.table, association_joins, Arel::Nodes::OuterJoin)
|
262
284
|
else
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
end
|
285
|
+
Polyamorous::JoinDependency.new(relation.klass, relation.table, association_joins)
|
286
|
+
end
|
287
|
+
join_dependency.instance_variable_set(:@alias_tracker, alias_tracker)
|
288
|
+
join_nodes.each do |join|
|
289
|
+
join_dependency.send(:alias_tracker).aliases[join.left.name.downcase] = 1
|
269
290
|
end
|
270
291
|
join_dependency
|
271
292
|
end
|
@@ -289,32 +310,23 @@ module Ransack
|
|
289
310
|
end
|
290
311
|
|
291
312
|
def build_association(name, parent = @base, klass = nil)
|
292
|
-
if ::ActiveRecord::VERSION::STRING
|
293
|
-
jd = Polyamorous::JoinDependency.new(
|
294
|
-
parent.base_klass,
|
295
|
-
Polyamorous::Join.new(name, @join_type, klass),
|
296
|
-
[]
|
297
|
-
)
|
298
|
-
found_association = jd.join_root.children.last
|
299
|
-
elsif ::ActiveRecord::VERSION::STRING == Constants::RAILS_5_2_0
|
300
|
-
alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(self.klass.connection, parent.table.name, [])
|
313
|
+
if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_0)
|
301
314
|
jd = Polyamorous::JoinDependency.new(
|
302
315
|
parent.base_klass,
|
303
|
-
parent.
|
316
|
+
parent.table,
|
304
317
|
Polyamorous::Join.new(name, @join_type, klass),
|
305
|
-
|
318
|
+
@join_type
|
306
319
|
)
|
307
320
|
found_association = jd.instance_variable_get(:@join_root).children.last
|
308
321
|
else
|
309
322
|
jd = Polyamorous::JoinDependency.new(
|
310
323
|
parent.base_klass,
|
311
|
-
parent.
|
312
|
-
Polyamorous::Join.new(name, @join_type, klass)
|
324
|
+
parent.table,
|
325
|
+
Polyamorous::Join.new(name, @join_type, klass)
|
313
326
|
)
|
314
327
|
found_association = jd.instance_variable_get(:@join_root).children.last
|
315
328
|
end
|
316
329
|
|
317
|
-
|
318
330
|
@associations_pot[found_association] = parent
|
319
331
|
|
320
332
|
# TODO maybe we dont need to push associations here, we could loop
|
@@ -322,40 +334,27 @@ module Ransack
|
|
322
334
|
@join_dependency.instance_variable_get(:@join_root).children.push found_association
|
323
335
|
|
324
336
|
# Builds the arel nodes properly for this association
|
325
|
-
if ::ActiveRecord::VERSION::STRING
|
326
|
-
@join_dependency.
|
337
|
+
if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_1)
|
338
|
+
@tables_pot[found_association] = @join_dependency.construct_tables_for_association!(jd.instance_variable_get(:@join_root), found_association)
|
327
339
|
else
|
328
|
-
@join_dependency.send(
|
329
|
-
:construct_tables!, jd.instance_variable_get(:@join_root), found_association
|
330
|
-
)
|
340
|
+
@join_dependency.send(:construct_tables!, jd.instance_variable_get(:@join_root))
|
331
341
|
end
|
332
342
|
|
333
343
|
# Leverage the stashed association functionality in AR
|
334
344
|
@object = @object.joins(jd)
|
335
|
-
|
336
345
|
found_association
|
337
346
|
end
|
338
347
|
|
339
348
|
def extract_joins(association)
|
340
349
|
parent = @join_dependency.instance_variable_get(:@join_root)
|
341
350
|
reflection = association.reflection
|
342
|
-
join_constraints = if ::ActiveRecord::VERSION::STRING
|
343
|
-
association.
|
344
|
-
parent.table,
|
345
|
-
parent.base_klass,
|
346
|
-
association,
|
347
|
-
Arel::Nodes::OuterJoin,
|
348
|
-
association.tables,
|
349
|
-
reflection.scope_chain,
|
350
|
-
reflection.chain
|
351
|
-
)
|
352
|
-
elsif ::ActiveRecord::VERSION::STRING <= Constants::RAILS_5_2_0
|
353
|
-
association.join_constraints(
|
351
|
+
join_constraints = if ::Gem::Version.new(::ActiveRecord::VERSION::STRING) >= ::Gem::Version.new(Constants::RAILS_6_1)
|
352
|
+
association.join_constraints_with_tables(
|
354
353
|
parent.table,
|
355
354
|
parent.base_klass,
|
356
355
|
Arel::Nodes::OuterJoin,
|
357
|
-
|
358
|
-
|
356
|
+
@join_dependency.instance_variable_get(:@alias_tracker),
|
357
|
+
@tables_pot[association]
|
359
358
|
)
|
360
359
|
else
|
361
360
|
association.join_constraints(
|