ransack 2.1.1 → 2.5.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.
Files changed (88) 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 +102 -0
  5. data/.github/workflows/rubocop.yml +20 -0
  6. data/.github/workflows/test.yml +163 -0
  7. data/.gitignore +1 -0
  8. data/.rubocop.yml +44 -0
  9. data/CHANGELOG.md +64 -1
  10. data/CONTRIBUTING.md +16 -11
  11. data/Gemfile +23 -17
  12. data/README.md +190 -57
  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 +17 -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_7.0_ruby_2/join_association.rb +1 -0
  27. data/lib/polyamorous/activerecord_7.0_ruby_2/join_dependency.rb +1 -0
  28. data/lib/polyamorous/activerecord_7.0_ruby_2/reflection.rb +1 -0
  29. data/lib/polyamorous/polyamorous.rb +24 -0
  30. data/lib/polyamorous.rb +1 -25
  31. data/lib/ransack/adapters/active_record/base.rb +5 -1
  32. data/lib/ransack/adapters/active_record/context.rb +71 -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 +13 -5
  36. data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -1
  37. data/lib/ransack/configuration.rb +31 -1
  38. data/lib/ransack/constants.rb +3 -5
  39. data/lib/ransack/context.rb +19 -18
  40. data/lib/ransack/helpers/form_builder.rb +8 -14
  41. data/lib/ransack/helpers/form_helper.rb +1 -1
  42. data/lib/ransack/helpers.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/locale/sv.yml +70 -0
  50. data/lib/ransack/nodes/attribute.rb +1 -1
  51. data/lib/ransack/nodes/condition.rb +7 -1
  52. data/lib/ransack/nodes/grouping.rb +1 -1
  53. data/lib/ransack/nodes/sort.rb +3 -3
  54. data/lib/ransack/nodes/value.rb +1 -1
  55. data/lib/ransack/predicate.rb +2 -1
  56. data/lib/ransack/search.rb +4 -1
  57. data/lib/ransack/translate.rb +115 -115
  58. data/lib/ransack/version.rb +1 -1
  59. data/lib/ransack.rb +3 -3
  60. data/ransack.gemspec +8 -23
  61. data/spec/blueprints/articles.rb +1 -1
  62. data/spec/blueprints/comments.rb +1 -1
  63. data/spec/blueprints/notes.rb +1 -1
  64. data/spec/blueprints/tags.rb +1 -1
  65. data/spec/console.rb +5 -5
  66. data/spec/helpers/polyamorous_helper.rb +3 -8
  67. data/spec/helpers/ransack_helper.rb +1 -1
  68. data/spec/{ransack → polyamorous}/join_association_spec.rb +8 -1
  69. data/spec/{ransack → polyamorous}/join_dependency_spec.rb +18 -7
  70. data/spec/{ransack → polyamorous}/join_spec.rb +0 -0
  71. data/spec/ransack/adapters/active_record/base_spec.rb +26 -15
  72. data/spec/ransack/adapters/active_record/context_spec.rb +60 -18
  73. data/spec/ransack/configuration_spec.rb +24 -0
  74. data/spec/ransack/helpers/form_helper_spec.rb +16 -16
  75. data/spec/ransack/nodes/condition_spec.rb +13 -0
  76. data/spec/ransack/nodes/grouping_spec.rb +2 -2
  77. data/spec/ransack/predicate_spec.rb +54 -2
  78. data/spec/ransack/search_spec.rb +238 -36
  79. data/spec/spec_helper.rb +10 -5
  80. data/spec/support/schema.rb +37 -3
  81. metadata +45 -139
  82. data/.travis.yml +0 -37
  83. data/lib/polyamorous/activerecord_5.0_ruby_2/join_association.rb +0 -2
  84. data/lib/polyamorous/activerecord_5.0_ruby_2/join_dependency.rb +0 -2
  85. data/lib/polyamorous/activerecord_5.1_ruby_2/join_association.rb +0 -32
  86. data/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +0 -112
  87. data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_association.rb +0 -32
  88. data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_dependency.rb +0 -113
@@ -15,9 +15,11 @@ module Ransack
15
15
  :translate, :to => :base
16
16
 
17
17
  def initialize(object, params = {}, options = {})
18
+ strip_whitespace = options.fetch(:strip_whitespace, Ransack.options[:strip_whitespace])
18
19
  params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
19
20
  if params.is_a? Hash
20
21
  params = params.dup
22
+ params = params.transform_values { |v| v.is_a?(String) && strip_whitespace ? v.strip : v }
21
23
  params.delete_if { |k, v| [*v].all?{ |i| i.blank? && i != false } }
22
24
  else
23
25
  params = {}
@@ -29,6 +31,7 @@ module Ransack
29
31
  )
30
32
  @scope_args = {}
31
33
  @sorts ||= []
34
+ @ignore_unknown_conditions = options[:ignore_unknown_conditions] == false ? false : true
32
35
  build(params.with_indifferent_access)
33
36
  end
34
37
 
@@ -44,7 +47,7 @@ module Ransack
44
47
  base.send("#{key}=", value)
45
48
  elsif @context.ransackable_scope?(key, @context.object)
46
49
  add_scope(key, value)
47
- elsif !Ransack.options[:ignore_unknown_conditions]
50
+ elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
48
51
  raise ArgumentError, "Invalid search term #{key}"
49
52
  end
50
53
  end
@@ -6,151 +6,151 @@ I18n.load_path += Dir[
6
6
 
7
7
  module Ransack
8
8
  module Translate
9
- def self.word(key, options = {})
10
- I18n.translate(:"ransack.#{key}", :default => key.to_s)
11
- end
12
-
13
- def self.predicate(key, options = {})
14
- I18n.translate(:"ransack.predicates.#{key}", :default => key.to_s)
15
- end
16
-
17
- def self.attribute(key, options = {})
18
- unless context = options.delete(:context)
19
- raise ArgumentError, "A context is required to translate attributes"
9
+ class << self
10
+ def word(key, options = {})
11
+ I18n.translate(:"ransack.#{key}", default: key.to_s)
20
12
  end
21
13
 
22
- original_name = key.to_s
23
- base_class = context.klass
24
- base_ancestors = base_class.ancestors.select {
25
- |x| x.respond_to?(:model_name)
26
- }
27
- attributes_str = original_name.dup # will be modified by ⬇
28
- predicate = Predicate.detect_and_strip_from_string!(attributes_str)
29
- attribute_names = attributes_str.split(/_and_|_or_/)
30
- combinator = attributes_str.match(/_and_/) ? :and : :or
31
- defaults = base_ancestors.map do |klass|
32
- "ransack.attributes.#{i18n_key(klass)}.#{original_name}".to_sym
14
+ def predicate(key, options = {})
15
+ I18n.translate(:"ransack.predicates.#{key}", default: key.to_s)
33
16
  end
34
17
 
35
- translated_names = attribute_names.map do |name|
36
- attribute_name(context, name, options[:include_associations])
37
- end
18
+ def attribute(key, options = {})
19
+ unless context = options.delete(:context)
20
+ raise ArgumentError, "A context is required to translate attributes"
21
+ end
38
22
 
39
- interpolations = {
40
- :attributes => translated_names.join(" #{Translate.word(combinator)} ")
41
- }
23
+ original_name = key.to_s
24
+ base_class = context.klass
25
+ base_ancestors = base_class.ancestors.select {
26
+ |x| x.respond_to?(:model_name)
27
+ }
28
+ attributes_str = original_name.dup # will be modified by ⬇
29
+ predicate = Predicate.detect_and_strip_from_string!(attributes_str)
30
+ attribute_names = attributes_str.split(/_and_|_or_/)
31
+ combinator = attributes_str =~ /_and_/ ? :and : :or
32
+ defaults = base_ancestors.map do |klass|
33
+ "ransack.attributes.#{i18n_key(klass)}.#{original_name}".to_sym
34
+ end
35
+ defaults << options.delete(:default) if options[:default]
42
36
 
43
- if predicate
44
- defaults << "%{attributes} %{predicate}".freeze
45
- interpolations[:predicate] = Translate.predicate(predicate)
46
- else
47
- defaults << "%{attributes}".freeze
48
- end
37
+ translated_names = attribute_names.map do |name|
38
+ attribute_name(context, name, options[:include_associations])
39
+ end
49
40
 
50
- defaults << options.delete(:default) if options[:default]
51
- options.reverse_merge! :count => 1, :default => defaults
52
- I18n.translate(defaults.shift, options.merge(interpolations))
53
- end
41
+ interpolations = {
42
+ attributes: translated_names.join(" #{Translate.word(combinator)} ")
43
+ }
54
44
 
55
- def self.association(key, options = {})
56
- unless context = options.delete(:context)
57
- raise ArgumentError, "A context is required to translate associations"
45
+ if predicate
46
+ defaults << "%{attributes} %{predicate}".freeze
47
+ interpolations[:predicate] = Translate.predicate(predicate)
48
+ else
49
+ defaults << "%{attributes}".freeze
50
+ end
51
+
52
+ options.reverse_merge! count: 1, default: defaults
53
+ I18n.translate(defaults.shift, **options.merge(interpolations))
58
54
  end
59
55
 
60
- defaults =
61
- if key.blank?
62
- [:"ransack.models.#{i18n_key(context.klass)}",
63
- :"#{context.klass.i18n_scope}.models.#{i18n_key(context.klass)}"]
64
- else
65
- [:"ransack.associations.#{i18n_key(context.klass)}.#{key}"]
56
+ def association(key, options = {})
57
+ unless context = options.delete(:context)
58
+ raise ArgumentError, "A context is required to translate associations"
66
59
  end
67
- defaults << context.traverse(key).model_name.human
68
- options = { :count => 1, :default => defaults }
69
- I18n.translate(defaults.shift, options)
70
- end
71
60
 
72
- private
61
+ defaults =
62
+ if key.blank?
63
+ [:"ransack.models.#{i18n_key(context.klass)}",
64
+ :"#{context.klass.i18n_scope}.models.#{i18n_key(context.klass)}"]
65
+ else
66
+ [:"ransack.associations.#{i18n_key(context.klass)}.#{key}"]
67
+ end
68
+ defaults << context.traverse(key).model_name.human
69
+ options = { :count => 1, :default => defaults }
70
+ I18n.translate(defaults.shift, **options)
71
+ end
73
72
 
74
- def self.attribute_name(context, name, include_associations = nil)
75
- @context, @name = context, name
76
- @assoc_path = context.association_path(name)
77
- @attr_name = @name.sub(/^#{@assoc_path}_/, ''.freeze)
78
- associated_class = @context.traverse(@assoc_path) if @assoc_path.present?
79
- @include_associated = include_associations && associated_class
73
+ private
80
74
 
81
- defaults = default_attribute_name << fallback_args
82
- options = { :count => 1, :default => defaults }
83
- interpolations = build_interpolations(associated_class)
75
+ def attribute_name(context, name, include_associations = nil)
76
+ @context, @name = context, name
77
+ @assoc_path = context.association_path(name)
78
+ @attr_name = @name.sub(/^#{@assoc_path}_/, ''.freeze)
79
+ associated_class = @context.traverse(@assoc_path) if @assoc_path.present?
80
+ @include_associated = include_associations && associated_class
84
81
 
85
- I18n.translate(defaults.shift, options.merge(interpolations))
86
- end
82
+ defaults = default_attribute_name << fallback_args
83
+ options = { count: 1, default: defaults }
84
+ interpolations = build_interpolations(associated_class)
87
85
 
88
- def self.default_attribute_name
89
- ["ransack.attributes.#{i18n_key(@context.klass)}.#{@name}".to_sym]
90
- end
86
+ I18n.translate(defaults.shift, **options.merge(interpolations))
87
+ end
91
88
 
92
- def self.fallback_args
93
- if @include_associated
94
- '%{association_name} %{attr_fallback_name}'.freeze
95
- else
96
- '%{attr_fallback_name}'.freeze
89
+ def default_attribute_name
90
+ ["ransack.attributes.#{i18n_key(@context.klass)}.#{@name}".to_sym]
97
91
  end
98
- end
99
92
 
100
- def self.build_interpolations(associated_class)
101
- {
102
- :attr_fallback_name => attr_fallback_name(associated_class),
103
- :association_name => association_name
104
- }
105
- .reject { |_, value| value.nil? }
106
- end
93
+ def fallback_args
94
+ if @include_associated
95
+ '%{association_name} %{attr_fallback_name}'.freeze
96
+ else
97
+ '%{attr_fallback_name}'.freeze
98
+ end
99
+ end
107
100
 
108
- def self.attr_fallback_name(associated_class)
109
- I18n.t(
110
- :"ransack.attributes.#{fallback_class(associated_class)}.#{@attr_name}",
111
- :default => default_interpolation(associated_class)
101
+ def build_interpolations(associated_class)
102
+ {
103
+ attr_fallback_name: attr_fallback_name(associated_class),
104
+ association_name: association_name
105
+ }.reject { |_, value| value.nil? }
106
+ end
107
+
108
+ def attr_fallback_name(associated_class)
109
+ I18n.t(
110
+ :"ransack.attributes.#{fallback_class(associated_class)}.#{@attr_name}",
111
+ default: default_interpolation(associated_class)
112
112
  )
113
- end
113
+ end
114
114
 
115
- def self.fallback_class(associated_class)
116
- i18n_key(associated_class || @context.klass)
117
- end
115
+ def fallback_class(associated_class)
116
+ i18n_key(associated_class || @context.klass)
117
+ end
118
118
 
119
- def self.association_name
120
- association(@assoc_path, :context => @context) if @include_associated
121
- end
119
+ def association_name
120
+ association(@assoc_path, context: @context) if @include_associated
121
+ end
122
122
 
123
- def self.default_interpolation(associated_class)
124
- [
125
- associated_attribute(associated_class),
126
- ".attributes.#{@attr_name}".to_sym,
127
- @attr_name.humanize
128
- ]
129
- .flatten
130
- end
123
+ def default_interpolation(associated_class)
124
+ [
125
+ associated_attribute(associated_class),
126
+ ".attributes.#{@attr_name}".to_sym,
127
+ @attr_name.humanize
128
+ ].flatten
129
+ end
131
130
 
132
- def self.associated_attribute(associated_class)
133
- if associated_class
134
- translated_attribute(associated_class)
135
- else
136
- translated_ancestor_attributes
131
+ def associated_attribute(associated_class)
132
+ if associated_class
133
+ translated_attribute(associated_class)
134
+ else
135
+ translated_ancestor_attributes
136
+ end
137
137
  end
138
- end
139
138
 
140
- def self.translated_attribute(associated_class)
141
- key = "#{associated_class.i18n_scope}.attributes.#{
139
+ def translated_attribute(associated_class)
140
+ key = "#{associated_class.i18n_scope}.attributes.#{
142
141
  i18n_key(associated_class)}.#{@attr_name}"
143
- ["#{key}.one".to_sym, key.to_sym]
144
- end
142
+ ["#{key}.one".to_sym, key.to_sym]
143
+ end
145
144
 
146
- def self.translated_ancestor_attributes
147
- @context.klass.ancestors
148
- .select { |ancestor| ancestor.respond_to?(:model_name) }
149
- .map { |ancestor| translated_attribute(ancestor) }
150
- end
145
+ def translated_ancestor_attributes
146
+ @context.klass.ancestors
147
+ .select { |ancestor| ancestor.respond_to?(:model_name) }
148
+ .map { |ancestor| translated_attribute(ancestor) }
149
+ end
151
150
 
152
- def self.i18n_key(klass)
153
- raise "not implemented"
151
+ def i18n_key(klass)
152
+ raise "not implemented"
153
+ end
154
154
  end
155
155
  end
156
156
  end
@@ -1,3 +1,3 @@
1
1
  module Ransack
2
- VERSION = '2.1.1'
2
+ VERSION = '2.5.0'
3
3
  end
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
data/ransack.gemspec CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
+
2
3
  $:.push File.expand_path("../lib", __FILE__)
3
4
  require "ransack/version"
4
5
 
@@ -6,36 +7,20 @@ Gem::Specification.new do |s|
6
7
  s.name = "ransack"
7
8
  s.version = Ransack::VERSION
8
9
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Ernie Miller", "Ryan Bigg", "Jon Atack","Sean Carroll"]
10
- s.email = ["ernie@erniemiller.org", "radarlistener@gmail.com", "jonnyatack@gmail.com","sfcarroll@gmail.com"]
10
+ s.authors = ["Ernie Miller", "Ryan Bigg", "Jon Atack", "Sean Carroll"]
11
+ s.email = ["ernie@erniemiller.org", "radarlistener@gmail.com", "jonnyatack@gmail.com", "sfcarroll@gmail.com"]
11
12
  s.homepage = "https://github.com/activerecord-hackery/ransack"
12
13
  s.summary = %q{Object-based searching for Active Record and Mongoid (currently).}
13
14
  s.description = %q{Ransack is the successor to the MetaSearch gem. It improves and expands upon MetaSearch's functionality, but does not have a 100%-compatible API.}
14
- s.required_ruby_version = '>= 1.9'
15
+ s.required_ruby_version = '>= 2.6'
15
16
  s.license = 'MIT'
16
17
 
17
- s.rubyforge_project = "ransack"
18
-
19
- s.add_dependency 'actionpack', '>= 5.0'
20
- s.add_dependency 'activerecord', '>= 5.0'
21
- s.add_dependency 'activesupport', '>= 5.0'
18
+ s.add_dependency 'activerecord', '>= 5.2.4'
19
+ s.add_dependency 'activesupport', '>= 5.2.4'
22
20
  s.add_dependency 'i18n'
23
- s.add_development_dependency 'rspec', '~> 3'
24
- s.add_development_dependency 'machinist', '~> 1.0.6'
25
- s.add_development_dependency 'faker', '~> 0.9.5'
26
- s.add_development_dependency 'sqlite3', '~> 1.3.3'
27
- s.add_development_dependency 'pg', '~> 0.21'
28
- s.add_development_dependency 'mysql2', '0.3.20'
29
- s.add_development_dependency 'pry', '0.10'
30
21
 
31
22
  s.files = `git ls-files`.split("\n")
32
-
33
- s.test_files = `git ls-files -- {test,spec,features}/*`
34
- .split("\n")
35
-
36
- s.executables = `git ls-files -- bin/*`
37
- .split("\n")
38
- .map { |f| File.basename(f) }
39
-
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
40
25
  s.require_paths = ["lib"]
41
26
  end
@@ -2,4 +2,4 @@ Article.blueprint do
2
2
  person
3
3
  title
4
4
  body
5
- end
5
+ end
@@ -2,4 +2,4 @@ Comment.blueprint do
2
2
  article
3
3
  person
4
4
  body
5
- end
5
+ end
@@ -2,4 +2,4 @@ Note.blueprint do
2
2
  note
3
3
  notable_type { "Article" }
4
4
  notable_id
5
- end
5
+ end
@@ -1,3 +1,3 @@
1
1
  Tag.blueprint do
2
2
  name { Sham.tag_name }
3
- end
3
+ end
data/spec/console.rb CHANGED
@@ -14,11 +14,11 @@ Sham.define do
14
14
  title { Faker::Lorem.sentence }
15
15
  body { Faker::Lorem.paragraph }
16
16
  salary { |index| 30000 + (index * 1000) }
17
- tag_name { Faker::Lorem.words(3).join(' ') }
18
- note { Faker::Lorem.words(7).join(' ') }
19
- only_admin { Faker::Lorem.words(3).join(' ') }
20
- only_search { Faker::Lorem.words(3).join(' ') }
21
- only_sort { Faker::Lorem.words(3).join(' ') }
17
+ tag_name { Faker::Lorem.words(number: 3).join(' ') }
18
+ note { Faker::Lorem.words(number: 7).join(' ') }
19
+ only_admin { Faker::Lorem.words(number: 3).join(' ') }
20
+ only_search { Faker::Lorem.words(number: 3).join(' ') }
21
+ only_sort { Faker::Lorem.words(number: 3).join(' ') }
22
22
  notable_id { |id| id }
23
23
  end
24
24
 
@@ -3,18 +3,13 @@ module PolyamorousHelper
3
3
  Polyamorous::JoinAssociation.new reflection, children, klass
4
4
  end
5
5
 
6
- if ActiveRecord::VERSION::STRING > "5.2.0"
6
+ if ActiveRecord.version >= ::Gem::Version.new("6.0.0.rc1")
7
7
  def new_join_dependency(klass, associations = {})
8
- Polyamorous::JoinDependency.new klass, klass.arel_table, associations
9
- end
10
- elsif ActiveRecord::VERSION::STRING == "5.2.0"
11
- def new_join_dependency(klass, associations = {})
12
- alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(klass.connection, klass.table_name, [])
13
- Polyamorous::JoinDependency.new klass, klass.arel_table, associations, alias_tracker
8
+ Polyamorous::JoinDependency.new klass, klass.arel_table, associations, Polyamorous::InnerJoin
14
9
  end
15
10
  else
16
11
  def new_join_dependency(klass, associations = {})
17
- Polyamorous::JoinDependency.new klass, associations, []
12
+ Polyamorous::JoinDependency.new klass, klass.arel_table, associations
18
13
  end
19
14
  end
20
15
 
@@ -6,4 +6,4 @@ module RansackHelper
6
6
  def quote_column_name(column)
7
7
  ActiveRecord::Base.connection.quote_column_name(column)
8
8
  end
9
- end
9
+ end
@@ -10,7 +10,14 @@ module Polyamorous
10
10
  new_join_association(reflection, parent.children, Article)
11
11
  }
12
12
 
13
- it 'leaves the orginal reflection intact for thread safety' do
13
+ subject { new_join_association(reflection, parent.children, Person) }
14
+
15
+ it 'respects polymorphism on equality test' do
16
+ expect(subject).to eq new_join_association(reflection, parent.children, Person)
17
+ expect(subject).not_to eq new_join_association(reflection, parent.children, Article)
18
+ end
19
+
20
+ it 'leaves the original reflection intact for thread safety' do
14
21
  reflection.instance_variable_set(:@klass, Article)
15
22
  join_association
16
23
  .swapping_reflection_klass(reflection, Person) do |new_reflection|
@@ -8,8 +8,8 @@ module Polyamorous
8
8
 
9
9
  specify { expect(subject.send(:join_root).drop(1).size)
10
10
  .to eq(2) }
11
- specify { expect(subject.send(:join_root).drop(1).map(&:join_type))
12
- .to be_all { Polyamorous::InnerJoin } }
11
+ specify { expect(subject.send(:join_root).drop(1).map(&:join_type).uniq)
12
+ .to eq [Polyamorous::InnerJoin] }
13
13
  end
14
14
 
15
15
  context 'with has_many :through association' do
@@ -38,8 +38,8 @@ module Polyamorous
38
38
  .to eq 2 }
39
39
  specify { expect(subject.send(:join_root).drop(1).map(&:join_type))
40
40
  .to eq [Polyamorous::OuterJoin, Polyamorous::OuterJoin] }
41
- specify { expect(subject.send(:join_root).drop(1).map(&:join_type))
42
- .to be_all { Polyamorous::OuterJoin } }
41
+ specify { expect(subject.send(:join_root).drop(1).map(&:join_type).uniq)
42
+ .to eq [Polyamorous::OuterJoin] }
43
43
  end
44
44
 
45
45
  context 'with polymorphic belongs_to join' do
@@ -59,8 +59,19 @@ module Polyamorous
59
59
 
60
60
  specify { expect(subject.send(:join_root).drop(1).size)
61
61
  .to eq 2 }
62
- specify { expect(subject.send(:join_root).drop(1).map(&:join_type))
63
- .to be_all { Polyamorous::InnerJoin } }
62
+ specify { expect(subject.send(:join_root).drop(1).map(&:join_type).uniq)
63
+ .to eq [Polyamorous::InnerJoin] }
64
+ specify { expect(subject.send(:join_root).drop(1).first.table_name)
65
+ .to eq 'people' }
66
+ specify { expect(subject.send(:join_root).drop(1)[1].table_name)
67
+ .to eq 'comments' }
68
+ end
69
+
70
+ context 'with polymorphic belongs_to join and nested join' do
71
+ subject { new_join_dependency Note,
72
+ new_join(:notable, :outer, Person) => :comments }
73
+ specify { expect(subject.send(:join_root).drop(1).size).to eq 2 }
74
+ specify { expect(subject.send(:join_root).drop(1).map(&:join_type)).to eq [Polyamorous::OuterJoin, Polyamorous::InnerJoin] }
64
75
  specify { expect(subject.send(:join_root).drop(1).first.table_name)
65
76
  .to eq 'people' }
66
77
  specify { expect(subject.send(:join_root).drop(1)[1].table_name)
@@ -68,7 +79,7 @@ module Polyamorous
68
79
  end
69
80
 
70
81
  context '#left_outer_join in Rails 5 overrides join type specified',
71
- if: ActiveRecord::VERSION::MAJOR >= 5 && ActiveRecord::VERSION::MINOR < 2 do
82
+ if: ActiveRecord::VERSION::MAJOR >= 5 && ActiveRecord::VERSION::MAJOR < 6 && ActiveRecord::VERSION::MINOR < 2 do
72
83
 
73
84
  let(:join_type_class) do
74
85
  new_join_dependency(
File without changes