ransack 2.4.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/cronjob.yml +6 -9
- data/.github/workflows/rubocop.yml +1 -1
- data/.github/workflows/test.yml +25 -34
- data/.nojekyll +0 -0
- data/CHANGELOG.md +90 -11
- data/CONTRIBUTING.md +4 -3
- data/README.md +45 -973
- data/docs/.gitignore +20 -0
- data/docs/.nojekyll +0 -0
- data/docs/babel.config.js +3 -0
- data/docs/blog/2022-03-27-ransack-3.0.0.md +20 -0
- data/docs/docs/getting-started/_category_.json +4 -0
- data/docs/docs/getting-started/advanced-mode.md +46 -0
- data/docs/docs/getting-started/configuration.md +47 -0
- data/docs/docs/getting-started/search-matches.md +67 -0
- data/docs/docs/getting-started/simple-mode.md +284 -0
- data/docs/docs/getting-started/sorting.md +79 -0
- data/docs/docs/getting-started/using-predicates.md +282 -0
- data/docs/docs/going-further/_category_.json +4 -0
- data/docs/docs/going-further/associations.md +70 -0
- data/docs/docs/going-further/custom-predicates.md +52 -0
- data/docs/docs/going-further/documentation.md +31 -0
- data/docs/docs/going-further/exporting-to-csv.md +49 -0
- data/docs/docs/going-further/external-guides.md +57 -0
- data/docs/docs/going-further/form-customisation.md +63 -0
- data/docs/docs/going-further/i18n.md +53 -0
- data/docs/{img → docs/going-further/img}/create_release.png +0 -0
- data/docs/docs/going-further/merging-searches.md +41 -0
- data/docs/docs/going-further/other-notes.md +428 -0
- data/docs/docs/going-further/ransackers.md +331 -0
- data/docs/docs/going-further/release_process.md +36 -0
- data/docs/docs/going-further/saving-queries.md +82 -0
- data/docs/docs/going-further/searching-postgres.md +57 -0
- data/docs/docs/intro.md +99 -0
- data/docs/docusaurus.config.js +108 -0
- data/docs/package-lock.json +9207 -0
- data/docs/package.json +37 -0
- data/docs/sidebars.js +31 -0
- data/docs/src/components/HomepageFeatures/index.js +64 -0
- data/docs/src/components/HomepageFeatures/styles.module.css +11 -0
- data/docs/src/css/custom.css +39 -0
- data/docs/src/pages/index.module.css +23 -0
- data/docs/src/pages/markdown-page.md +7 -0
- data/docs/static/.nojekyll +0 -0
- data/docs/static/img/docusaurus.png +0 -0
- data/docs/static/img/favicon.ico +0 -0
- data/docs/static/img/logo.svg +1 -0
- data/docs/static/img/tutorial/docsVersionDropdown.png +0 -0
- data/docs/static/img/tutorial/localeDropdown.png +0 -0
- data/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
- data/docs/static/img/undraw_docusaurus_react.svg +170 -0
- data/docs/static/img/undraw_docusaurus_tree.svg +40 -0
- data/{logo → docs/static/logo}/ransack-h.png +0 -0
- data/{logo → docs/static/logo}/ransack-h.svg +0 -0
- data/{logo → docs/static/logo}/ransack-v.png +0 -0
- data/{logo → docs/static/logo}/ransack-v.svg +0 -0
- data/{logo → docs/static/logo}/ransack.png +0 -0
- data/{logo → docs/static/logo}/ransack.svg +0 -0
- data/docs/yarn.lock +7671 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +20 -1
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +0 -1
- data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +11 -1
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +0 -4
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +0 -1
- data/lib/polyamorous/{activerecord_6.2_ruby_2 → activerecord_7.0_ruby_2}/join_association.rb +0 -0
- data/lib/polyamorous/{activerecord_6.2_ruby_2 → activerecord_7.0_ruby_2}/join_dependency.rb +0 -0
- data/lib/polyamorous/{activerecord_6.2_ruby_2 → activerecord_7.0_ruby_2}/reflection.rb +0 -0
- data/lib/polyamorous.rb +1 -0
- data/lib/ransack/adapters/active_record/base.rb +1 -3
- data/lib/ransack/adapters/active_record/context.rb +7 -2
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +10 -9
- data/lib/ransack/configuration.rb +16 -2
- data/lib/ransack/helpers/form_helper.rb +11 -3
- data/lib/ransack/locale/sv.yml +70 -0
- data/lib/ransack/nodes/sort.rb +2 -2
- data/lib/ransack/search.rb +4 -3
- data/lib/ransack/translate.rb +1 -1
- data/lib/ransack/version.rb +1 -1
- data/ransack.gemspec +4 -4
- data/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
- data/spec/polyamorous/join_association_spec.rb +1 -6
- data/spec/polyamorous/join_dependency_spec.rb +0 -16
- data/spec/ransack/adapters/active_record/base_spec.rb +28 -11
- data/spec/ransack/configuration_spec.rb +14 -0
- data/spec/ransack/helpers/form_helper_spec.rb +33 -2
- data/spec/ransack/nodes/condition_spec.rb +13 -0
- data/spec/ransack/search_spec.rb +140 -27
- data/spec/support/schema.rb +49 -0
- metadata +72 -25
- data/docs/release_process.md +0 -20
- data/lib/polyamorous/activerecord_5.2_ruby_2/join_association.rb +0 -24
- data/lib/polyamorous/activerecord_5.2_ruby_2/join_dependency.rb +0 -79
- data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +0 -11
|
@@ -1 +1,20 @@
|
|
|
1
|
-
|
|
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
|
+
end
|
|
20
|
+
end
|
|
@@ -1 +1,11 @@
|
|
|
1
|
-
|
|
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
|
data/lib/polyamorous/{activerecord_6.2_ruby_2 → activerecord_7.0_ruby_2}/join_association.rb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/lib/polyamorous.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'polyamorous/polyamorous'
|
|
@@ -4,7 +4,6 @@ module Ransack
|
|
|
4
4
|
module Base
|
|
5
5
|
|
|
6
6
|
def self.extended(base)
|
|
7
|
-
alias :search :ransack unless base.respond_to? :search
|
|
8
7
|
base.class_eval do
|
|
9
8
|
class_attribute :_ransackers
|
|
10
9
|
class_attribute :_ransack_aliases
|
|
@@ -14,7 +13,6 @@ module Ransack
|
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
def ransack(params = {}, options = {})
|
|
17
|
-
ActiveSupport::Deprecation.warn("#search is deprecated and will be removed in 2.3, please use #ransack instead") if __callee__ == :search
|
|
18
16
|
Search.new(self, params, options)
|
|
19
17
|
end
|
|
20
18
|
|
|
@@ -70,7 +68,7 @@ module Ransack
|
|
|
70
68
|
end
|
|
71
69
|
|
|
72
70
|
# ransack_scope_skip_sanitize_args, by default, returns an empty array.
|
|
73
|
-
# i.e. use the sanitize_scope_args setting to
|
|
71
|
+
# i.e. use the sanitize_scope_args setting to determine if args should be converted.
|
|
74
72
|
# For overriding with a list of scopes which should be passed the args as-is.
|
|
75
73
|
#
|
|
76
74
|
def ransackable_scopes_skip_sanitize_args
|
|
@@ -44,9 +44,13 @@ module Ransack
|
|
|
44
44
|
else
|
|
45
45
|
case Ransack.options[:postgres_fields_sort_option]
|
|
46
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"
|
|
47
|
+
scope_or_sort = scope_or_sort.direction == :asc ? Arel.sql("#{scope_or_sort.to_sql} NULLS FIRST") : Arel.sql("#{scope_or_sort.to_sql} NULLS LAST")
|
|
48
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"
|
|
49
|
+
scope_or_sort = scope_or_sort.direction == :asc ? Arel.sql("#{scope_or_sort.to_sql} NULLS LAST") : Arel.sql("#{scope_or_sort.to_sql} NULLS FIRST")
|
|
50
|
+
when :nulls_always_first
|
|
51
|
+
scope_or_sort = Arel.sql("#{scope_or_sort.to_sql} NULLS FIRST")
|
|
52
|
+
when :nulls_always_last
|
|
53
|
+
scope_or_sort = Arel.sql("#{scope_or_sort.to_sql} NULLS LAST")
|
|
50
54
|
end
|
|
51
55
|
|
|
52
56
|
relation = relation.order(scope_or_sort)
|
|
@@ -139,6 +143,7 @@ module Ransack
|
|
|
139
143
|
stashed.eql?(association)
|
|
140
144
|
}
|
|
141
145
|
@object.joins_values.delete_if { |jd|
|
|
146
|
+
jd.instance_variables.include?(:@join_root) &&
|
|
142
147
|
jd.instance_variable_get(:@join_root).children.map(&:object_id) == [association.object_id]
|
|
143
148
|
}
|
|
144
149
|
end
|
|
@@ -47,18 +47,19 @@ module Ransack
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def casted_array?(predicate)
|
|
50
|
-
(predicate.
|
|
51
|
-
(predicate.respond_to?(:val) && predicate.val.is_a?(Array)) # Rails 5.2, 6.0
|
|
50
|
+
value_from(predicate).is_a?(Array) && predicate.is_a?(Arel::Nodes::Casted)
|
|
52
51
|
end
|
|
53
52
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
def value_from(predicate)
|
|
54
|
+
if predicate.respond_to?(:value)
|
|
55
|
+
predicate.value # Rails 6.1
|
|
56
|
+
elsif predicate.respond_to?(:val)
|
|
57
|
+
predicate.val # Rails 6.0
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
def format_values_for(predicate)
|
|
62
|
+
value_from(predicate).map do |val|
|
|
62
63
|
val.is_a?(String) ? Arel::Nodes.build_quoted(val) : val
|
|
63
64
|
end
|
|
64
65
|
end
|
|
@@ -34,7 +34,8 @@ module Ransack
|
|
|
34
34
|
:down_arrow => '▲'.freeze,
|
|
35
35
|
:default_arrow => nil,
|
|
36
36
|
:sanitize_scope_args => true,
|
|
37
|
-
:postgres_fields_sort_option => nil
|
|
37
|
+
:postgres_fields_sort_option => nil,
|
|
38
|
+
:strip_whitespace => true
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
def configure
|
|
@@ -148,7 +149,7 @@ module Ransack
|
|
|
148
149
|
# User may want to configure it like this:
|
|
149
150
|
#
|
|
150
151
|
# Ransack.configure do |c|
|
|
151
|
-
# c.postgres_fields_sort_option = :nulls_first # or :
|
|
152
|
+
# c.postgres_fields_sort_option = :nulls_first # or e.g. :nulls_always_last
|
|
152
153
|
# end
|
|
153
154
|
#
|
|
154
155
|
# See this feature: https://www.postgresql.org/docs/13/queries-order.html
|
|
@@ -170,6 +171,19 @@ module Ransack
|
|
|
170
171
|
self.options[:hide_sort_order_indicators] = boolean
|
|
171
172
|
end
|
|
172
173
|
|
|
174
|
+
# By default, Ransack displays strips all whitespace when searching for a string.
|
|
175
|
+
# The default may be globally changed in an initializer file like
|
|
176
|
+
# `config/initializers/ransack.rb` as follows:
|
|
177
|
+
#
|
|
178
|
+
# Ransack.configure do |config|
|
|
179
|
+
# # Enable whitespace stripping for string searches
|
|
180
|
+
# config.strip_whitespace = true
|
|
181
|
+
# end
|
|
182
|
+
#
|
|
183
|
+
def strip_whitespace=(boolean)
|
|
184
|
+
self.options[:strip_whitespace] = boolean
|
|
185
|
+
end
|
|
186
|
+
|
|
173
187
|
def arel_predicate_with_suffix(arel_predicate, suffix)
|
|
174
188
|
if arel_predicate === Proc
|
|
175
189
|
proc { |v| "#{arel_predicate.call(v)}#{suffix}" }
|
|
@@ -130,12 +130,20 @@ module Ransack
|
|
|
130
130
|
|
|
131
131
|
def url_options
|
|
132
132
|
@params.merge(
|
|
133
|
-
@options.merge(
|
|
133
|
+
@options.except(:class).merge(
|
|
134
134
|
@search.context.search_key => search_and_sort_params))
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
def html_options(args)
|
|
138
|
-
|
|
138
|
+
if args.empty?
|
|
139
|
+
html_options = @options
|
|
140
|
+
else
|
|
141
|
+
deprecation_message = "Passing two trailing hashes to `sort_link` is deprecated, merge the trailing hashes into a single one."
|
|
142
|
+
caller_location = caller_locations(2, 2).first
|
|
143
|
+
warn "#{deprecation_message} (called at #{caller_location.path}:#{caller_location.lineno})"
|
|
144
|
+
html_options = extract_options_and_mutate_args!(args)
|
|
145
|
+
end
|
|
146
|
+
|
|
139
147
|
html_options.merge(
|
|
140
148
|
class: [['sort_link'.freeze, @current_dir], html_options[:class]]
|
|
141
149
|
.compact.join(' '.freeze)
|
|
@@ -145,7 +153,7 @@ module Ransack
|
|
|
145
153
|
private
|
|
146
154
|
|
|
147
155
|
def parameters_hash(params)
|
|
148
|
-
if
|
|
156
|
+
if params.respond_to?(:to_unsafe_h)
|
|
149
157
|
params.to_unsafe_h
|
|
150
158
|
else
|
|
151
159
|
params
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
sv:
|
|
2
|
+
ransack:
|
|
3
|
+
search: "sök"
|
|
4
|
+
predicate: "predikat"
|
|
5
|
+
and: "och"
|
|
6
|
+
or: "eller"
|
|
7
|
+
any: "vilken som"
|
|
8
|
+
all: "alla"
|
|
9
|
+
combinator: "kombinator"
|
|
10
|
+
attribute: "attribut"
|
|
11
|
+
value: "värde"
|
|
12
|
+
condition: "villkor"
|
|
13
|
+
sort: "sortera"
|
|
14
|
+
asc: "stigande"
|
|
15
|
+
desc: "fallande"
|
|
16
|
+
predicates:
|
|
17
|
+
eq: "lika med"
|
|
18
|
+
eq_any: "lika med vilket som"
|
|
19
|
+
eq_all: "lika med alla"
|
|
20
|
+
not_eq: "inte lika med"
|
|
21
|
+
not_eq_any: "inte lika med någon"
|
|
22
|
+
not_eq_all: "inte lika med alla"
|
|
23
|
+
matches: "matchar"
|
|
24
|
+
matches_any: "matchar någon"
|
|
25
|
+
matches_all: "matchar alla"
|
|
26
|
+
does_not_match: "matchar inte"
|
|
27
|
+
does_not_match_any: "matchar inte någon"
|
|
28
|
+
does_not_match_all: "matchar inte alla"
|
|
29
|
+
lt: "mindre än"
|
|
30
|
+
lt_any: "mindre än någon"
|
|
31
|
+
lt_all: "mindre än alla"
|
|
32
|
+
lteq: "mindre än eller lika med"
|
|
33
|
+
lteq_any: "mindre än eller lika med någon"
|
|
34
|
+
lteq_all: "mindre än eller lika med alla"
|
|
35
|
+
gt: "större än"
|
|
36
|
+
gt_any: "större än någon"
|
|
37
|
+
gt_all: "större än alla"
|
|
38
|
+
gteq: "större än eller lika med"
|
|
39
|
+
gteq_any: "större än eller lika med någon"
|
|
40
|
+
gteq_all: "större än eller lika med alla"
|
|
41
|
+
in: "i"
|
|
42
|
+
in_any: "i någon"
|
|
43
|
+
in_all: "i alla"
|
|
44
|
+
not_in: "inte i"
|
|
45
|
+
not_in_any: "inte i någon"
|
|
46
|
+
not_in_all: "inte i alla"
|
|
47
|
+
cont: "innehåller"
|
|
48
|
+
cont_any: "innehåller någon"
|
|
49
|
+
cont_all: "innehåller alla"
|
|
50
|
+
not_cont: "innehåller inte"
|
|
51
|
+
not_cont_any: "innehåller inte någon"
|
|
52
|
+
not_cont_all: "innehåller inte alla"
|
|
53
|
+
start: "börjar med"
|
|
54
|
+
start_any: "börjar med någon"
|
|
55
|
+
start_all: "börjar med alla"
|
|
56
|
+
not_start: "börjar inte med"
|
|
57
|
+
not_start_any: "börjar inte med någon"
|
|
58
|
+
not_start_all: "börjar inte med alla"
|
|
59
|
+
end: "slutar med"
|
|
60
|
+
end_any: "slutar med någon"
|
|
61
|
+
end_all: "slutar med alla"
|
|
62
|
+
not_end: "slutar inte med"
|
|
63
|
+
not_end_any: "slutar inte med någon"
|
|
64
|
+
not_end_all: "slutar inte med alla"
|
|
65
|
+
'true': "är sant"
|
|
66
|
+
'false': "är falskt"
|
|
67
|
+
present: "existerar"
|
|
68
|
+
blank: "är tom"
|
|
69
|
+
'null': "är null"
|
|
70
|
+
not_null: "är inte null"
|
data/lib/ransack/nodes/sort.rb
CHANGED
data/lib/ransack/search.rb
CHANGED
|
@@ -15,10 +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
|
|
21
|
-
params = params.transform_values { |v| v.is_a?(String) ? v.strip : v }
|
|
22
|
+
params = params.transform_values { |v| v.is_a?(String) && strip_whitespace ? v.strip : v }
|
|
22
23
|
params.delete_if { |k, v| [*v].all?{ |i| i.blank? && i != false } }
|
|
23
24
|
else
|
|
24
25
|
params = {}
|
|
@@ -42,10 +43,10 @@ module Ransack
|
|
|
42
43
|
collapse_multiparameter_attributes!(params).each do |key, value|
|
|
43
44
|
if ['s'.freeze, 'sorts'.freeze].freeze.include?(key)
|
|
44
45
|
send("#{key}=", value)
|
|
45
|
-
elsif base.attribute_method?(key)
|
|
46
|
-
base.send("#{key}=", value)
|
|
47
46
|
elsif @context.ransackable_scope?(key, @context.object)
|
|
48
47
|
add_scope(key, value)
|
|
48
|
+
elsif base.attribute_method?(key)
|
|
49
|
+
base.send("#{key}=", value)
|
|
49
50
|
elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
|
|
50
51
|
raise ArgumentError, "Invalid search term #{key}"
|
|
51
52
|
end
|
data/lib/ransack/translate.rb
CHANGED
|
@@ -32,6 +32,7 @@ module Ransack
|
|
|
32
32
|
defaults = base_ancestors.map do |klass|
|
|
33
33
|
"ransack.attributes.#{i18n_key(klass)}.#{original_name}".to_sym
|
|
34
34
|
end
|
|
35
|
+
defaults << options.delete(:default) if options[:default]
|
|
35
36
|
|
|
36
37
|
translated_names = attribute_names.map do |name|
|
|
37
38
|
attribute_name(context, name, options[:include_associations])
|
|
@@ -48,7 +49,6 @@ module Ransack
|
|
|
48
49
|
defaults << "%{attributes}".freeze
|
|
49
50
|
end
|
|
50
51
|
|
|
51
|
-
defaults << options.delete(:default) if options[:default]
|
|
52
52
|
options.reverse_merge! count: 1, default: defaults
|
|
53
53
|
I18n.translate(defaults.shift, **options.merge(interpolations))
|
|
54
54
|
end
|
data/lib/ransack/version.rb
CHANGED
data/ransack.gemspec
CHANGED
|
@@ -7,16 +7,16 @@ Gem::Specification.new do |s|
|
|
|
7
7
|
s.name = "ransack"
|
|
8
8
|
s.version = Ransack::VERSION
|
|
9
9
|
s.platform = Gem::Platform::RUBY
|
|
10
|
-
s.authors = ["Ernie Miller", "Ryan Bigg", "Jon Atack", "Sean Carroll"]
|
|
10
|
+
s.authors = ["Ernie Miller", "Ryan Bigg", "Jon Atack", "Sean Carroll", "David Rodríguez"]
|
|
11
11
|
s.email = ["ernie@erniemiller.org", "radarlistener@gmail.com", "jonnyatack@gmail.com", "sfcarroll@gmail.com"]
|
|
12
12
|
s.homepage = "https://github.com/activerecord-hackery/ransack"
|
|
13
|
-
s.summary = %q{Object-based searching for Active Record
|
|
13
|
+
s.summary = %q{Object-based searching for Active Record.}
|
|
14
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.}
|
|
15
15
|
s.required_ruby_version = '>= 2.6'
|
|
16
16
|
s.license = 'MIT'
|
|
17
17
|
|
|
18
|
-
s.add_dependency 'activerecord', '>=
|
|
19
|
-
s.add_dependency 'activesupport', '>=
|
|
18
|
+
s.add_dependency 'activerecord', '>= 6.0.4'
|
|
19
|
+
s.add_dependency 'activesupport', '>= 6.0.4'
|
|
20
20
|
s.add_dependency 'i18n'
|
|
21
21
|
|
|
22
22
|
s.files = `git ls-files`.split("\n")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Polyamorous
|
|
4
|
+
describe "ActiveRecord Compatibility" do
|
|
5
|
+
it 'works with self joins and includes' do
|
|
6
|
+
trade_account = Account.create!
|
|
7
|
+
Account.create!(trade_account: trade_account)
|
|
8
|
+
|
|
9
|
+
accounts = Account.joins(:trade_account).includes(:trade_account, :agent_account)
|
|
10
|
+
account = accounts.first
|
|
11
|
+
|
|
12
|
+
expect(account.agent_account).to be_nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -12,12 +12,7 @@ module Polyamorous
|
|
|
12
12
|
|
|
13
13
|
subject { new_join_association(reflection, parent.children, Person) }
|
|
14
14
|
|
|
15
|
-
it '
|
|
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 orginal reflection intact for thread safety' do
|
|
15
|
+
it 'leaves the original reflection intact for thread safety' do
|
|
21
16
|
reflection.instance_variable_set(:@klass, Article)
|
|
22
17
|
join_association
|
|
23
18
|
.swapping_reflection_klass(reflection, Person) do |new_reflection|
|
|
@@ -77,21 +77,5 @@ module Polyamorous
|
|
|
77
77
|
specify { expect(subject.send(:join_root).drop(1)[1].table_name)
|
|
78
78
|
.to eq 'comments' }
|
|
79
79
|
end
|
|
80
|
-
|
|
81
|
-
context '#left_outer_join in Rails 5 overrides join type specified',
|
|
82
|
-
if: ActiveRecord::VERSION::MAJOR >= 5 && ActiveRecord::VERSION::MAJOR < 6 && ActiveRecord::VERSION::MINOR < 2 do
|
|
83
|
-
|
|
84
|
-
let(:join_type_class) do
|
|
85
|
-
new_join_dependency(
|
|
86
|
-
Person,
|
|
87
|
-
new_join(:articles)
|
|
88
|
-
).join_constraints(
|
|
89
|
-
[],
|
|
90
|
-
Arel::Nodes::OuterJoin
|
|
91
|
-
).first.joins.map(&:class)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
specify { expect(join_type_class).to eq [Arel::Nodes::OuterJoin] }
|
|
95
|
-
end
|
|
96
80
|
end
|
|
97
81
|
end
|
|
@@ -8,7 +8,6 @@ module Ransack
|
|
|
8
8
|
subject { ::ActiveRecord::Base }
|
|
9
9
|
|
|
10
10
|
it { should respond_to :ransack }
|
|
11
|
-
it { should respond_to :search }
|
|
12
11
|
|
|
13
12
|
describe '#search' do
|
|
14
13
|
subject { Person.ransack }
|
|
@@ -44,12 +43,12 @@ module Ransack
|
|
|
44
43
|
|
|
45
44
|
it 'applies stringy boolean scopes with true value in an array' do
|
|
46
45
|
s = Person.ransack('of_age' => ['true'])
|
|
47
|
-
expect(s.result.to_sql).to (include 'age >= 18')
|
|
46
|
+
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{(age >= '18')} : 'age >= 18')
|
|
48
47
|
end
|
|
49
48
|
|
|
50
49
|
it 'applies stringy boolean scopes with false value in an array' do
|
|
51
50
|
s = Person.ransack('of_age' => ['false'])
|
|
52
|
-
expect(s.result.to_sql).to (include 'age < 18')
|
|
51
|
+
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age < '18'} : 'age < 18')
|
|
53
52
|
end
|
|
54
53
|
|
|
55
54
|
it 'ignores unlisted scopes' do
|
|
@@ -69,15 +68,25 @@ module Ransack
|
|
|
69
68
|
|
|
70
69
|
it 'passes values to scopes' do
|
|
71
70
|
s = Person.ransack('over_age' => 18)
|
|
72
|
-
expect(s.result.to_sql).to (include 'age > 18')
|
|
71
|
+
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '18'} : 'age > 18')
|
|
73
72
|
end
|
|
74
73
|
|
|
75
74
|
it 'chains scopes' do
|
|
76
75
|
s = Person.ransack('over_age' => 18, 'active' => true)
|
|
77
|
-
expect(s.result.to_sql).to (include 'age > 18')
|
|
76
|
+
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '18'} : 'age > 18')
|
|
78
77
|
expect(s.result.to_sql).to (include 'active = 1')
|
|
79
78
|
end
|
|
80
79
|
|
|
80
|
+
it 'applies scopes that define string SQL joins' do
|
|
81
|
+
allow(Article)
|
|
82
|
+
.to receive(:ransackable_scopes)
|
|
83
|
+
.and_return([:latest_comment_cont])
|
|
84
|
+
|
|
85
|
+
# Including a negative condition to test removing the scope
|
|
86
|
+
s = Search.new(Article, notes_note_not_eq: 'Test', latest_comment_cont: 'Test')
|
|
87
|
+
expect(s.result.to_sql).to include 'latest_comment'
|
|
88
|
+
end
|
|
89
|
+
|
|
81
90
|
context "with sanitize_custom_scope_booleans set to false" do
|
|
82
91
|
before(:all) do
|
|
83
92
|
Ransack.configure { |c| c.sanitize_custom_scope_booleans = false }
|
|
@@ -89,12 +98,12 @@ module Ransack
|
|
|
89
98
|
|
|
90
99
|
it 'passes true values to scopes' do
|
|
91
100
|
s = Person.ransack('over_age' => 1)
|
|
92
|
-
expect(s.result.to_sql).to (include 'age > 1')
|
|
101
|
+
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '1'} : 'age > 1')
|
|
93
102
|
end
|
|
94
103
|
|
|
95
104
|
it 'passes false values to scopes' do
|
|
96
105
|
s = Person.ransack('over_age' => 0)
|
|
97
|
-
expect(s.result.to_sql).to (include 'age > 0')
|
|
106
|
+
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '0'} : 'age > 0')
|
|
98
107
|
end
|
|
99
108
|
end
|
|
100
109
|
|
|
@@ -107,12 +116,12 @@ module Ransack
|
|
|
107
116
|
|
|
108
117
|
it 'passes true values to scopes' do
|
|
109
118
|
s = Person.ransack('over_age' => 1)
|
|
110
|
-
expect(s.result.to_sql).to (include 'age > 1')
|
|
119
|
+
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '1'} : 'age > 1')
|
|
111
120
|
end
|
|
112
121
|
|
|
113
122
|
it 'passes false values to scopes' do
|
|
114
123
|
s = Person.ransack('over_age' => 0)
|
|
115
|
-
expect(s.result.to_sql).to (include 'age > 0')
|
|
124
|
+
expect(s.result.to_sql).to (include rails7_and_mysql ? %q{age > '0'} : 'age > 0')
|
|
116
125
|
end
|
|
117
126
|
end
|
|
118
127
|
|
|
@@ -123,7 +132,7 @@ module Ransack
|
|
|
123
132
|
end
|
|
124
133
|
|
|
125
134
|
it 'raises exception if ransack! called with unknown condition' do
|
|
126
|
-
expect { Person.ransack!(unknown_attr_eq: 'Ernie') }.to raise_error
|
|
135
|
+
expect { Person.ransack!(unknown_attr_eq: 'Ernie') }.to raise_error(ArgumentError)
|
|
127
136
|
end
|
|
128
137
|
|
|
129
138
|
it 'does not modify the parameters' do
|
|
@@ -314,7 +323,11 @@ module Ransack
|
|
|
314
323
|
end
|
|
315
324
|
|
|
316
325
|
it 'should function correctly with a multi-parameter attribute' do
|
|
317
|
-
::ActiveRecord::
|
|
326
|
+
if ::ActiveRecord::VERSION::MAJOR >= 7
|
|
327
|
+
::ActiveRecord.default_timezone = :utc
|
|
328
|
+
else
|
|
329
|
+
::ActiveRecord::Base.default_timezone = :utc
|
|
330
|
+
end
|
|
318
331
|
Time.zone = 'UTC'
|
|
319
332
|
|
|
320
333
|
date = Date.current
|
|
@@ -690,6 +703,10 @@ module Ransack
|
|
|
690
703
|
it { should eq [] }
|
|
691
704
|
end
|
|
692
705
|
|
|
706
|
+
private
|
|
707
|
+
def rails7_and_mysql
|
|
708
|
+
::ActiveRecord::VERSION::MAJOR >= 7 && ENV['DB'] == 'mysql'
|
|
709
|
+
end
|
|
693
710
|
end
|
|
694
711
|
end
|
|
695
712
|
end
|
|
@@ -45,6 +45,20 @@ module Ransack
|
|
|
45
45
|
Ransack.options = default
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
it 'should have default value for strip_whitespace' do
|
|
49
|
+
expect(Ransack.options[:strip_whitespace]).to eq true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'changes default search key parameter' do
|
|
53
|
+
default = Ransack.options.clone
|
|
54
|
+
|
|
55
|
+
Ransack.configure { |c| c.strip_whitespace = false }
|
|
56
|
+
|
|
57
|
+
expect(Ransack.options[:strip_whitespace]).to eq false
|
|
58
|
+
|
|
59
|
+
Ransack.options = default
|
|
60
|
+
end
|
|
61
|
+
|
|
48
62
|
it 'should have default values for arrows' do
|
|
49
63
|
expect(Ransack.options[:up_arrow]).to eq '▼'
|
|
50
64
|
expect(Ransack.options[:down_arrow]).to eq '▲'
|
|
@@ -469,8 +469,7 @@ module Ransack
|
|
|
469
469
|
it { should match /exist\=existing/ }
|
|
470
470
|
end
|
|
471
471
|
|
|
472
|
-
context 'using a real ActionController::Parameter object'
|
|
473
|
-
if: ::ActiveRecord::VERSION::MAJOR > 3 do
|
|
472
|
+
context 'using a real ActionController::Parameter object' do
|
|
474
473
|
|
|
475
474
|
describe 'with symbol q:, #sort_link should include search params' do
|
|
476
475
|
subject { @controller.view_context.sort_link(Person.ransack, :name) }
|
|
@@ -727,6 +726,38 @@ module Ransack
|
|
|
727
726
|
it { should match /Block label ▼/ }
|
|
728
727
|
end
|
|
729
728
|
|
|
729
|
+
describe '#sort_link with class option' do
|
|
730
|
+
subject { @controller.view_context
|
|
731
|
+
.sort_link(
|
|
732
|
+
[:main_app, Person.ransack(sorts: ['name desc'])],
|
|
733
|
+
:name,
|
|
734
|
+
class: 'people', controller: 'people'
|
|
735
|
+
)
|
|
736
|
+
}
|
|
737
|
+
it { should match /class="sort_link desc people"/ }
|
|
738
|
+
it { should_not match /people\?class=people/ }
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
describe '#sort_link with class option workaround' do
|
|
742
|
+
it "generates a correct link and prints a deprecation" do
|
|
743
|
+
expect do
|
|
744
|
+
link = @controller.view_context
|
|
745
|
+
.sort_link(
|
|
746
|
+
[:main_app, Person.ransack(sorts: ['name desc'])],
|
|
747
|
+
:name,
|
|
748
|
+
'name',
|
|
749
|
+
{ controller: 'people' },
|
|
750
|
+
class: 'people'
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
expect(link).to match(/class="sort_link desc people"/)
|
|
754
|
+
expect(link).not_to match(/people\?class=people/)
|
|
755
|
+
end.to output(
|
|
756
|
+
/Passing two trailing hashes to `sort_link` is deprecated, merge the trailing hashes into a single one\. \(called at #{Regexp.escape(__FILE__)}:/
|
|
757
|
+
).to_stderr
|
|
758
|
+
end
|
|
759
|
+
end
|
|
760
|
+
|
|
730
761
|
describe '#search_form_for with default format' do
|
|
731
762
|
subject { @controller.view_context
|
|
732
763
|
.search_form_for(Person.ransack) {} }
|
|
@@ -3,6 +3,19 @@ require 'spec_helper'
|
|
|
3
3
|
module Ransack
|
|
4
4
|
module Nodes
|
|
5
5
|
describe Condition do
|
|
6
|
+
context 'bug report #1245' do
|
|
7
|
+
it 'preserves tuple behavior' do
|
|
8
|
+
ransack_hash = {
|
|
9
|
+
m: 'and',
|
|
10
|
+
g: [
|
|
11
|
+
{ title_type_in: ['["title 1", ""]'] }
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
sql = Article.ransack(ransack_hash).result.to_sql
|
|
16
|
+
expect(sql).to include("IN (('title 1', ''))")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
6
19
|
|
|
7
20
|
context 'with an alias' do
|
|
8
21
|
subject {
|