ransack 2.1.1 → 2.4.2

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.
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(