ransack 2.1.1 → 2.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/SECURITY.md +12 -0
  4. data/.github/workflows/cronjob.yml +105 -0
  5. data/.github/workflows/rubocop.yml +20 -0
  6. data/.github/workflows/test.yml +154 -0
  7. data/.gitignore +1 -0
  8. data/.rubocop.yml +44 -0
  9. data/CHANGELOG.md +55 -1
  10. data/CONTRIBUTING.md +13 -11
  11. data/Gemfile +23 -17
  12. data/README.md +119 -52
  13. data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +78 -0
  14. data/bug_report_templates/test-ransacker-arel-present-predicate.rb +71 -0
  15. data/docs/img/create_release.png +0 -0
  16. data/docs/release_process.md +20 -0
  17. data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_association.rb +2 -9
  18. data/lib/polyamorous/{activerecord_5.2.1_ruby_2 → activerecord_5.2_ruby_2}/join_dependency.rb +25 -3
  19. data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +11 -0
  20. data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +1 -0
  21. data/lib/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +80 -0
  22. data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +1 -0
  23. data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +74 -0
  24. data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +93 -0
  25. data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +1 -0
  26. data/lib/polyamorous/activerecord_6.2_ruby_2/join_association.rb +1 -0
  27. data/lib/polyamorous/activerecord_6.2_ruby_2/join_dependency.rb +1 -0
  28. data/lib/polyamorous/activerecord_6.2_ruby_2/reflection.rb +1 -0
  29. data/lib/{polyamorous.rb → polyamorous/polyamorous.rb} +4 -5
  30. data/lib/ransack.rb +3 -3
  31. data/lib/ransack/adapters/active_record/base.rb +4 -0
  32. data/lib/ransack/adapters/active_record/context.rb +67 -68
  33. data/lib/ransack/adapters/active_record/ransack/constants.rb +18 -3
  34. data/lib/ransack/adapters/active_record/ransack/context.rb +2 -6
  35. data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +12 -5
  36. data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -1
  37. data/lib/ransack/configuration.rb +17 -1
  38. data/lib/ransack/constants.rb +3 -5
  39. data/lib/ransack/context.rb +19 -18
  40. data/lib/ransack/helpers.rb +1 -1
  41. data/lib/ransack/helpers/form_builder.rb +8 -14
  42. data/lib/ransack/helpers/form_helper.rb +1 -1
  43. data/lib/ransack/locale/az.yml +1 -1
  44. data/lib/ransack/locale/ca.yml +70 -0
  45. data/lib/ransack/locale/es.yml +22 -22
  46. data/lib/ransack/locale/fa.yml +70 -0
  47. data/lib/ransack/locale/fi.yml +71 -0
  48. data/lib/ransack/locale/sk.yml +70 -0
  49. data/lib/ransack/nodes/attribute.rb +1 -1
  50. data/lib/ransack/nodes/condition.rb +7 -1
  51. data/lib/ransack/nodes/grouping.rb +1 -1
  52. data/lib/ransack/nodes/sort.rb +1 -1
  53. data/lib/ransack/nodes/value.rb +1 -1
  54. data/lib/ransack/predicate.rb +2 -1
  55. data/lib/ransack/search.rb +3 -1
  56. data/lib/ransack/translate.rb +115 -115
  57. data/lib/ransack/version.rb +1 -1
  58. data/ransack.gemspec +8 -23
  59. data/spec/blueprints/articles.rb +1 -1
  60. data/spec/blueprints/comments.rb +1 -1
  61. data/spec/blueprints/notes.rb +1 -1
  62. data/spec/blueprints/tags.rb +1 -1
  63. data/spec/console.rb +5 -5
  64. data/spec/helpers/polyamorous_helper.rb +3 -8
  65. data/spec/helpers/ransack_helper.rb +1 -1
  66. data/spec/{ransack → polyamorous}/join_association_spec.rb +7 -0
  67. data/spec/{ransack → polyamorous}/join_dependency_spec.rb +18 -7
  68. data/spec/{ransack → polyamorous}/join_spec.rb +0 -0
  69. data/spec/ransack/adapters/active_record/base_spec.rb +9 -6
  70. data/spec/ransack/adapters/active_record/context_spec.rb +60 -18
  71. data/spec/ransack/configuration_spec.rb +10 -0
  72. data/spec/ransack/helpers/form_helper_spec.rb +16 -16
  73. data/spec/ransack/nodes/grouping_spec.rb +2 -2
  74. data/spec/ransack/predicate_spec.rb +54 -2
  75. data/spec/ransack/search_spec.rb +127 -15
  76. data/spec/spec_helper.rb +10 -5
  77. data/spec/support/schema.rb +14 -3
  78. metadata +41 -137
  79. data/.travis.yml +0 -37
  80. data/lib/polyamorous/activerecord_5.0_ruby_2/join_association.rb +0 -2
  81. data/lib/polyamorous/activerecord_5.0_ruby_2/join_dependency.rb +0 -2
  82. data/lib/polyamorous/activerecord_5.1_ruby_2/join_association.rb +0 -32
  83. data/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +0 -112
  84. data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_association.rb +0 -32
  85. 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)
@@ -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 build_constraint(klass, table, key, foreign_table, foreign_key)
23
- if reflection.polymorphic?
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
@@ -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,11 @@
1
+ module Polyamorous
2
+ module ReflectionExtensions
3
+ def join_scope(table, foreign_table, foreign_klass)
4
+ if respond_to?(:polymorphic?) && polymorphic?
5
+ super.where!(foreign_table[foreign_type].eq(klass.name))
6
+ else
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -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
- ar_version = ::ActiveRecord::VERSION::STRING[0,5] if ar_version >= "5.2"
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
- Arel::SelectManager.new(@object.table),
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
- else
115
+ end
116
+
115
117
  [
116
118
  Arel::SelectManager.new(@object.table),
117
- @join_dependency.join_constraints(@object.joins_values, @join_type)
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.right.expr.left
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
- if ::ActiveRecord::VERSION::STRING < Constants::RAILS_5_2_0
252
- join_dependency = Polyamorous::JoinDependency.new(relation.klass, association_joins, join_list)
253
- join_nodes.each do |join|
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
- alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(self.klass.connection, relation.table.name, join_list)
264
- join_dependency = Polyamorous::JoinDependency.new(relation.klass, relation.table, association_joins)
265
- join_dependency.instance_variable_set(:@alias_tracker, alias_tracker)
266
- join_nodes.each do |join|
267
- join_dependency.send(:alias_tracker).aliases[join.left.name.downcase] = 1
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 < Constants::RAILS_5_2_0
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.base_klass.arel_table,
316
+ parent.table,
304
317
  Polyamorous::Join.new(name, @join_type, klass),
305
- alias_tracker
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.base_klass.arel_table,
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 > Constants::RAILS_5_2_0
326
- @join_dependency.send(:construct_tables!, jd.instance_variable_get(:@join_root))
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 < Constants::RAILS_5_1
343
- association.join_constraints(
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
- association.tables,
358
- reflection.chain
356
+ @join_dependency.instance_variable_get(:@alias_tracker),
357
+ @tables_pot[association]
359
358
  )
360
359
  else
361
360
  association.join_constraints(