ransack 2.3.2 → 4.1.1
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/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/codeql.yml +72 -0
- data/.github/workflows/cronjob.yml +99 -0
- data/.github/workflows/deploy.yml +35 -0
- data/.github/workflows/rubocop.yml +20 -0
- data/.github/workflows/test-deploy.yml +29 -0
- data/.github/workflows/test.yml +131 -0
- data/.nojekyll +0 -0
- data/.rubocop.yml +50 -0
- data/CHANGELOG.md +251 -1
- data/CONTRIBUTING.md +51 -29
- data/Gemfile +12 -10
- data/README.md +45 -907
- data/bug_report_templates/test-ransack-scope-and-column-same-name.rb +78 -0
- data/bug_report_templates/test-ransacker-arel-present-predicate.rb +75 -0
- data/docs/.gitignore +19 -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 +288 -0
- data/docs/docs/getting-started/sorting.md +71 -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/acts-as-taggable-on.md +114 -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 +43 -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/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/polymorphic-search.md +46 -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/going-further/wiki-contributors.md +82 -0
- data/docs/docs/intro.md +99 -0
- data/docs/docusaurus.config.js +120 -0
- data/docs/package.json +42 -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/docs/yarn.lock +8879 -0
- data/lib/polyamorous/activerecord/join_association.rb +70 -0
- data/{polyamorous/lib/polyamorous/activerecord_6.0_ruby_2 → lib/polyamorous/activerecord}/join_dependency.rb +33 -12
- data/lib/polyamorous/activerecord/reflection.rb +11 -0
- data/{polyamorous/lib → lib/polyamorous}/polyamorous.rb +3 -4
- data/lib/ransack/adapters/active_record/base.rb +83 -10
- data/lib/ransack/adapters/active_record/context.rb +56 -44
- data/lib/ransack/configuration.rb +53 -10
- data/lib/ransack/constants.rb +126 -4
- data/lib/ransack/context.rb +34 -5
- data/lib/ransack/helpers/form_builder.rb +6 -6
- data/lib/ransack/helpers/form_helper.rb +14 -5
- data/lib/ransack/helpers.rb +1 -1
- data/lib/ransack/locale/sv.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +3 -3
- data/lib/ransack/nodes/condition.rb +80 -9
- data/lib/ransack/nodes/grouping.rb +4 -4
- data/lib/ransack/nodes/node.rb +1 -1
- data/lib/ransack/nodes/sort.rb +3 -3
- data/lib/ransack/nodes/value.rb +3 -3
- data/lib/ransack/predicate.rb +1 -1
- data/lib/ransack/ransacker.rb +1 -1
- data/lib/ransack/search.rb +15 -7
- data/lib/ransack/translate.rb +6 -6
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +38 -2
- data/lib/ransack.rb +5 -8
- data/ransack.gemspec +9 -15
- data/spec/blueprints/articles.rb +1 -1
- data/spec/blueprints/comments.rb +1 -1
- data/spec/blueprints/notes.rb +1 -1
- data/spec/blueprints/tags.rb +1 -1
- data/spec/console.rb +5 -5
- data/spec/helpers/polyamorous_helper.rb +2 -8
- data/spec/helpers/ransack_helper.rb +1 -1
- data/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
- data/spec/{ransack → polyamorous}/join_association_spec.rb +3 -1
- data/spec/{ransack → polyamorous}/join_dependency_spec.rb +0 -16
- data/spec/ransack/adapters/active_record/base_spec.rb +125 -16
- data/spec/ransack/adapters/active_record/context_spec.rb +19 -18
- data/spec/ransack/configuration_spec.rb +33 -9
- data/spec/ransack/helpers/form_builder_spec.rb +8 -8
- data/spec/ransack/helpers/form_helper_spec.rb +109 -20
- data/spec/ransack/nodes/condition_spec.rb +37 -0
- data/spec/ransack/nodes/grouping_spec.rb +2 -2
- data/spec/ransack/nodes/value_spec.rb +115 -0
- data/spec/ransack/predicate_spec.rb +37 -2
- data/spec/ransack/search_spec.rb +238 -30
- data/spec/ransack/translate_spec.rb +1 -1
- data/spec/spec_helper.rb +7 -5
- data/spec/support/schema.rb +108 -11
- metadata +98 -62
- data/.travis.yml +0 -47
- data/lib/ransack/adapters/active_record/ransack/constants.rb +0 -128
- data/lib/ransack/adapters/active_record/ransack/context.rb +0 -55
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +0 -61
- data/lib/ransack/adapters/active_record/ransack/translate.rb +0 -8
- data/lib/ransack/adapters/active_record/ransack/visitor.rb +0 -47
- data/lib/ransack/adapters.rb +0 -64
- data/lib/ransack/nodes.rb +0 -8
- data/polyamorous/lib/polyamorous/activerecord_5.2_ruby_2/join_association.rb +0 -20
- data/polyamorous/lib/polyamorous/activerecord_5.2_ruby_2/join_dependency.rb +0 -79
- data/polyamorous/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +0 -12
- data/polyamorous/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +0 -2
- data/polyamorous/lib/polyamorous/version.rb +0 -3
- data/polyamorous/polyamorous.gemspec +0 -27
- /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/{polyamorous/lib → lib}/polyamorous/join.rb +0 -0
- /data/{polyamorous/lib → lib}/polyamorous/swapping_reflection_class.rb +0 -0
- /data/{polyamorous/lib → lib}/polyamorous/tree_node.rb +0 -0
- /data/lib/ransack/{adapters/active_record.rb → active_record.rb} +0 -0
- /data/spec/{ransack → polyamorous}/join_spec.rb +0 -0
data/lib/ransack/constants.rb
CHANGED
|
@@ -36,7 +36,7 @@ module Ransack
|
|
|
36
36
|
'lt'.freeze, 'lteq'.freeze,
|
|
37
37
|
'gt'.freeze, 'gteq'.freeze,
|
|
38
38
|
'in'.freeze, 'not_in'.freeze
|
|
39
|
-
|
|
39
|
+
].freeze
|
|
40
40
|
A_S_I = ['a'.freeze, 's'.freeze, 'i'.freeze].freeze
|
|
41
41
|
|
|
42
42
|
EQ = 'eq'.freeze
|
|
@@ -45,10 +45,132 @@ module Ransack
|
|
|
45
45
|
NOT_EQ_ALL = 'not_eq_all'.freeze
|
|
46
46
|
CONT = 'cont'.freeze
|
|
47
47
|
|
|
48
|
-
RAILS_6_0 = '6.0.0'.freeze
|
|
49
|
-
|
|
50
48
|
RANSACK_SLASH_SEARCHES = 'ransack/searches'.freeze
|
|
51
49
|
RANSACK_SLASH_SEARCHES_SLASH_SEARCH = 'ransack/searches/search'.freeze
|
|
50
|
+
|
|
51
|
+
DISTINCT = 'DISTINCT '.freeze
|
|
52
|
+
|
|
53
|
+
DERIVED_PREDICATES = [
|
|
54
|
+
[CONT, {
|
|
55
|
+
arel_predicate: 'matches'.freeze,
|
|
56
|
+
formatter: proc { |v| "%#{escape_wildcards(v)}%" }
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
['not_cont'.freeze, {
|
|
60
|
+
arel_predicate: 'does_not_match'.freeze,
|
|
61
|
+
formatter: proc { |v| "%#{escape_wildcards(v)}%" }
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
['i_cont'.freeze, {
|
|
65
|
+
arel_predicate: 'matches'.freeze,
|
|
66
|
+
formatter: proc { |v| "%#{escape_wildcards(v.downcase)}%" },
|
|
67
|
+
case_insensitive: true
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
['not_i_cont'.freeze, {
|
|
71
|
+
arel_predicate: 'does_not_match'.freeze,
|
|
72
|
+
formatter: proc { |v| "%#{escape_wildcards(v.downcase)}%" },
|
|
73
|
+
case_insensitive: true
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
['start'.freeze, {
|
|
77
|
+
arel_predicate: 'matches'.freeze,
|
|
78
|
+
formatter: proc { |v| "#{escape_wildcards(v)}%" }
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
['not_start'.freeze, {
|
|
82
|
+
arel_predicate: 'does_not_match'.freeze,
|
|
83
|
+
formatter: proc { |v| "#{escape_wildcards(v)}%" }
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
['end'.freeze, {
|
|
87
|
+
arel_predicate: 'matches'.freeze,
|
|
88
|
+
formatter: proc { |v| "%#{escape_wildcards(v)}" }
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
['not_end'.freeze, {
|
|
92
|
+
arel_predicate: 'does_not_match'.freeze,
|
|
93
|
+
formatter: proc { |v| "%#{escape_wildcards(v)}" }
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
['true'.freeze, {
|
|
97
|
+
arel_predicate: proc { |v| v ? EQ : NOT_EQ },
|
|
98
|
+
compounds: false,
|
|
99
|
+
type: :boolean,
|
|
100
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
101
|
+
formatter: proc { |v| true }
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
['not_true'.freeze, {
|
|
105
|
+
arel_predicate: proc { |v| v ? NOT_EQ : EQ },
|
|
106
|
+
compounds: false,
|
|
107
|
+
type: :boolean,
|
|
108
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
109
|
+
formatter: proc { |v| true }
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
['false'.freeze, {
|
|
113
|
+
arel_predicate: proc { |v| v ? EQ : NOT_EQ },
|
|
114
|
+
compounds: false,
|
|
115
|
+
type: :boolean,
|
|
116
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
117
|
+
formatter: proc { |v| false }
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
['not_false'.freeze, {
|
|
121
|
+
arel_predicate: proc { |v| v ? NOT_EQ : EQ },
|
|
122
|
+
compounds: false,
|
|
123
|
+
type: :boolean,
|
|
124
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
125
|
+
formatter: proc { |v| false }
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
['present'.freeze, {
|
|
129
|
+
arel_predicate: proc { |v| v ? NOT_EQ_ALL : EQ_ANY },
|
|
130
|
+
compounds: false,
|
|
131
|
+
type: :boolean,
|
|
132
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
133
|
+
formatter: proc { |v| [nil, ''.freeze].freeze }
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
['blank'.freeze, {
|
|
137
|
+
arel_predicate: proc { |v| v ? EQ_ANY : NOT_EQ_ALL },
|
|
138
|
+
compounds: false,
|
|
139
|
+
type: :boolean,
|
|
140
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
141
|
+
formatter: proc { |v| [nil, ''.freeze].freeze }
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
['null'.freeze, {
|
|
145
|
+
arel_predicate: proc { |v| v ? EQ : NOT_EQ },
|
|
146
|
+
compounds: false,
|
|
147
|
+
type: :boolean,
|
|
148
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
149
|
+
formatter: proc { |v| nil }
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
['not_null'.freeze, {
|
|
153
|
+
arel_predicate: proc { |v| v ? NOT_EQ : EQ },
|
|
154
|
+
compounds: false,
|
|
155
|
+
type: :boolean,
|
|
156
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
157
|
+
formatter: proc { |v| nil } }
|
|
158
|
+
]
|
|
159
|
+
].freeze
|
|
160
|
+
|
|
161
|
+
module_function
|
|
162
|
+
# replace % \ to \% \\
|
|
163
|
+
def escape_wildcards(unescaped)
|
|
164
|
+
case ActiveRecord::Base.connection.adapter_name
|
|
165
|
+
when "Mysql2".freeze
|
|
166
|
+
# Necessary for MySQL
|
|
167
|
+
unescaped.to_s.gsub(/([\\%_])/, '\\\\\\1')
|
|
168
|
+
when "PostgreSQL".freeze
|
|
169
|
+
# Necessary for PostgreSQL
|
|
170
|
+
unescaped.to_s.gsub(/([\\%_.])/, '\\\\\\1')
|
|
171
|
+
else
|
|
172
|
+
unescaped
|
|
173
|
+
end
|
|
174
|
+
end
|
|
52
175
|
end
|
|
53
176
|
end
|
|
54
|
-
|
data/lib/ransack/context.rb
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
require 'ransack/visitor'
|
|
2
|
-
Ransack::Adapters.object_mapper.require_context
|
|
3
2
|
|
|
4
3
|
module Ransack
|
|
5
4
|
class Context
|
|
6
5
|
attr_reader :search, :object, :klass, :base, :engine, :arel_visitor
|
|
7
6
|
attr_accessor :auth_object, :search_key
|
|
7
|
+
attr_reader :arel_visitor
|
|
8
8
|
|
|
9
9
|
class << self
|
|
10
10
|
|
|
11
11
|
def for_class(klass, options = {})
|
|
12
|
-
|
|
12
|
+
if klass < ActiveRecord::Base
|
|
13
|
+
Adapters::ActiveRecord::Context.new(klass, options)
|
|
14
|
+
end
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def for_object(object, options = {})
|
|
16
|
-
|
|
18
|
+
case object
|
|
19
|
+
when ActiveRecord::Relation
|
|
20
|
+
Adapters::ActiveRecord::Context.new(object.klass, options)
|
|
21
|
+
end
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
def for(object, options = {})
|
|
@@ -30,11 +35,35 @@ module Ransack
|
|
|
30
35
|
end # << self
|
|
31
36
|
|
|
32
37
|
def initialize(object, options = {})
|
|
33
|
-
|
|
38
|
+
@object = relation_for(object)
|
|
39
|
+
@klass = @object.klass
|
|
40
|
+
@join_dependency = join_dependency(@object)
|
|
41
|
+
@join_type = options[:join_type] || Polyamorous::OuterJoin
|
|
42
|
+
@search_key = options[:search_key] || Ransack.options[:search_key]
|
|
43
|
+
@associations_pot = {}
|
|
44
|
+
@tables_pot = {}
|
|
45
|
+
@lock_associations = []
|
|
46
|
+
|
|
47
|
+
@base = @join_dependency.instance_variable_get(:@join_root)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def bind_pair_for(key)
|
|
51
|
+
@bind_pairs ||= {}
|
|
52
|
+
|
|
53
|
+
@bind_pairs[key] ||= begin
|
|
54
|
+
parent, attr_name = get_parent_and_attribute_name(key.to_s)
|
|
55
|
+
[parent, attr_name] if parent && attr_name
|
|
56
|
+
end
|
|
34
57
|
end
|
|
35
58
|
|
|
36
59
|
def klassify(obj)
|
|
37
|
-
|
|
60
|
+
if Class === obj && ::ActiveRecord::Base > obj
|
|
61
|
+
obj
|
|
62
|
+
elsif obj.respond_to? :klass
|
|
63
|
+
obj.klass
|
|
64
|
+
else
|
|
65
|
+
raise ArgumentError, "Don't know how to klassify #{obj.inspect}"
|
|
66
|
+
end
|
|
38
67
|
end
|
|
39
68
|
|
|
40
69
|
# Convert a string representing a chain of associations and an attribute
|
|
@@ -33,7 +33,7 @@ module Ransack
|
|
|
33
33
|
text = args.first
|
|
34
34
|
i18n = options[:i18n] || {}
|
|
35
35
|
text ||= object.translate(
|
|
36
|
-
method, i18n.reverse_merge(:
|
|
36
|
+
method, i18n.reverse_merge(include_associations: true)
|
|
37
37
|
) if object.respond_to? :translate
|
|
38
38
|
super(method, text, options, &block)
|
|
39
39
|
end
|
|
@@ -45,9 +45,9 @@ module Ransack
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def attribute_select(options = nil, html_options = nil, action = nil)
|
|
48
|
-
options
|
|
49
|
-
html_options
|
|
50
|
-
action
|
|
48
|
+
options ||= {}
|
|
49
|
+
html_options ||= {}
|
|
50
|
+
action ||= Constants::SEARCH
|
|
51
51
|
default = options.delete(:default)
|
|
52
52
|
raise ArgumentError, formbuilder_error_message(
|
|
53
53
|
"#{action}_select") unless object.respond_to?(:context)
|
|
@@ -240,7 +240,7 @@ module Ransack
|
|
|
240
240
|
def get_attribute_element(action, base)
|
|
241
241
|
begin
|
|
242
242
|
[
|
|
243
|
-
Translate.association(base, :
|
|
243
|
+
Translate.association(base, context: object.context),
|
|
244
244
|
collection_for_base(action, base)
|
|
245
245
|
]
|
|
246
246
|
rescue UntraversableAssociationError
|
|
@@ -253,7 +253,7 @@ module Ransack
|
|
|
253
253
|
[
|
|
254
254
|
attr_from_base_and_column(base, c),
|
|
255
255
|
Translate.attribute(
|
|
256
|
-
attr_from_base_and_column(base, c), :
|
|
256
|
+
attr_from_base_and_column(base, c), context: object.context
|
|
257
257
|
)
|
|
258
258
|
]
|
|
259
259
|
end
|
|
@@ -129,13 +129,21 @@ module Ransack
|
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
def url_options
|
|
132
|
-
@params.merge(
|
|
133
|
-
@options.merge(
|
|
132
|
+
@params.except(:host).merge(
|
|
133
|
+
@options.except(:class, :data, :host).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
|
|
@@ -172,7 +180,8 @@ module Ransack
|
|
|
172
180
|
end
|
|
173
181
|
|
|
174
182
|
def search_params
|
|
175
|
-
@params[@search.context.search_key]
|
|
183
|
+
query_params = @params[@search.context.search_key]
|
|
184
|
+
query_params.is_a?(Hash) ? query_params : {}
|
|
176
185
|
end
|
|
177
186
|
|
|
178
187
|
def sort_params
|
data/lib/ransack/helpers.rb
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
require 'ransack/helpers/form_builder'
|
|
2
|
-
require 'ransack/helpers/form_helper'
|
|
2
|
+
require 'ransack/helpers/form_helper'
|
|
@@ -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"
|
|
@@ -5,8 +5,8 @@ module Ransack
|
|
|
5
5
|
|
|
6
6
|
attr_reader :name, :ransacker_args
|
|
7
7
|
|
|
8
|
-
delegate :blank?, :present?, :
|
|
9
|
-
delegate :engine, :
|
|
8
|
+
delegate :blank?, :present?, to: :name
|
|
9
|
+
delegate :engine, to: :context
|
|
10
10
|
|
|
11
11
|
def initialize(context, name = nil, ransacker_args = [])
|
|
12
12
|
super(context)
|
|
@@ -30,7 +30,7 @@ module Ransack
|
|
|
30
30
|
|
|
31
31
|
def type
|
|
32
32
|
if ransacker
|
|
33
|
-
|
|
33
|
+
ransacker.type
|
|
34
34
|
else
|
|
35
35
|
context.type_for(self)
|
|
36
36
|
end
|
|
@@ -2,8 +2,8 @@ module Ransack
|
|
|
2
2
|
module Nodes
|
|
3
3
|
class Condition < Node
|
|
4
4
|
i18n_word :attribute, :predicate, :combinator, :value
|
|
5
|
-
i18n_alias :
|
|
6
|
-
:
|
|
5
|
+
i18n_alias a: :attribute, p: :predicate,
|
|
6
|
+
m: :combinator, v: :value
|
|
7
7
|
|
|
8
8
|
attr_accessor :predicate
|
|
9
9
|
|
|
@@ -15,10 +15,10 @@ module Ransack
|
|
|
15
15
|
if attributes.size > 0 && predicate
|
|
16
16
|
condition = self.new(context)
|
|
17
17
|
condition.build(
|
|
18
|
-
:
|
|
19
|
-
:
|
|
20
|
-
:
|
|
21
|
-
:
|
|
18
|
+
a: attributes,
|
|
19
|
+
p: predicate.name,
|
|
20
|
+
m: combinator,
|
|
21
|
+
v: predicate.wants_array ? Array(values) : [values]
|
|
22
22
|
)
|
|
23
23
|
# TODO: Figure out what to do with multiple types of attributes,
|
|
24
24
|
# if anything. Tempted to go with "garbage in, garbage out" here.
|
|
@@ -127,7 +127,6 @@ module Ransack
|
|
|
127
127
|
alias :m= :combinator=
|
|
128
128
|
alias :m :combinator
|
|
129
129
|
|
|
130
|
-
|
|
131
130
|
# == build_attribute
|
|
132
131
|
#
|
|
133
132
|
# This method was originally called from Nodes::Grouping#new_condition
|
|
@@ -263,7 +262,6 @@ module Ransack
|
|
|
263
262
|
attr.attr
|
|
264
263
|
end
|
|
265
264
|
|
|
266
|
-
|
|
267
265
|
def default_type
|
|
268
266
|
predicate.type || (attributes.first && attributes.first.type)
|
|
269
267
|
end
|
|
@@ -285,12 +283,85 @@ module Ransack
|
|
|
285
283
|
predicate.negative?
|
|
286
284
|
end
|
|
287
285
|
|
|
286
|
+
def arel_predicate
|
|
287
|
+
predicate = attributes.map { |attribute|
|
|
288
|
+
association = attribute.parent
|
|
289
|
+
if negative? && attribute.associated_collection?
|
|
290
|
+
query = context.build_correlated_subquery(association)
|
|
291
|
+
context.remove_association(association)
|
|
292
|
+
if self.predicate_name == 'not_null' && self.value
|
|
293
|
+
query.where(format_predicate(attribute))
|
|
294
|
+
Arel::Nodes::In.new(context.primary_key, Arel.sql(query.to_sql))
|
|
295
|
+
else
|
|
296
|
+
query.where(format_predicate(attribute).not)
|
|
297
|
+
Arel::Nodes::NotIn.new(context.primary_key, Arel.sql(query.to_sql))
|
|
298
|
+
end
|
|
299
|
+
else
|
|
300
|
+
format_predicate(attribute)
|
|
301
|
+
end
|
|
302
|
+
}.reduce(combinator_method)
|
|
303
|
+
|
|
304
|
+
if replace_right_node?(predicate)
|
|
305
|
+
# Replace right node object to plain integer value in order to avoid
|
|
306
|
+
# ActiveModel::RangeError from Arel::Node::Casted.
|
|
307
|
+
# The error can be ignored here because RDBMSs accept large numbers
|
|
308
|
+
# in condition clauses.
|
|
309
|
+
plain_value = predicate.right.value
|
|
310
|
+
predicate.right = plain_value
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
predicate
|
|
314
|
+
end
|
|
315
|
+
|
|
288
316
|
private
|
|
289
317
|
|
|
318
|
+
def combinator_method
|
|
319
|
+
combinator === Constants::OR ? :or : :and
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def format_predicate(attribute)
|
|
323
|
+
arel_pred = arel_predicate_for_attribute(attribute)
|
|
324
|
+
arel_values = formatted_values_for_attribute(attribute)
|
|
325
|
+
predicate = attr_value_for_attribute(attribute).public_send(arel_pred, arel_values)
|
|
326
|
+
|
|
327
|
+
if in_predicate?(predicate)
|
|
328
|
+
predicate.right = predicate.right.map do |pr|
|
|
329
|
+
casted_array?(pr) ? format_values_for(pr) : pr
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
predicate
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def in_predicate?(predicate)
|
|
337
|
+
return unless defined?(Arel::Nodes::Casted)
|
|
338
|
+
predicate.class == Arel::Nodes::In || predicate.class == Arel::Nodes::NotIn
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def casted_array?(predicate)
|
|
342
|
+
predicate.value.is_a?(Array) && predicate.is_a?(Arel::Nodes::Casted)
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def format_values_for(predicate)
|
|
346
|
+
predicate.value.map do |val|
|
|
347
|
+
val.is_a?(String) ? Arel::Nodes.build_quoted(val) : val
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def replace_right_node?(predicate)
|
|
352
|
+
return false unless predicate.is_a?(Arel::Nodes::Binary)
|
|
353
|
+
|
|
354
|
+
arel_node = predicate.right
|
|
355
|
+
return false unless arel_node.is_a?(Arel::Nodes::Casted)
|
|
356
|
+
|
|
357
|
+
relation, name = arel_node.attribute.values
|
|
358
|
+
attribute_type = relation.type_for_attribute(name).type
|
|
359
|
+
attribute_type == :integer && arel_node.value.is_a?(Integer)
|
|
360
|
+
end
|
|
361
|
+
|
|
290
362
|
def valid_combinator?
|
|
291
363
|
attributes.size < 2 || Constants::AND_OR.include?(combinator)
|
|
292
364
|
end
|
|
293
|
-
|
|
294
365
|
end
|
|
295
366
|
end
|
|
296
367
|
end
|
|
@@ -7,9 +7,9 @@ module Ransack
|
|
|
7
7
|
alias :m= :combinator=
|
|
8
8
|
|
|
9
9
|
i18n_word :condition, :and, :or
|
|
10
|
-
i18n_alias :
|
|
10
|
+
i18n_alias c: :condition, n: :and, o: :or
|
|
11
11
|
|
|
12
|
-
delegate :each, :
|
|
12
|
+
delegate :each, to: :values
|
|
13
13
|
|
|
14
14
|
def initialize(context, combinator = nil)
|
|
15
15
|
super(context)
|
|
@@ -22,7 +22,7 @@ module Ransack
|
|
|
22
22
|
|
|
23
23
|
def translate(key, options = {})
|
|
24
24
|
super or Translate.attribute(
|
|
25
|
-
key.to_s, options.merge(:
|
|
25
|
+
key.to_s, options.merge(context: context)
|
|
26
26
|
)
|
|
27
27
|
end
|
|
28
28
|
|
|
@@ -108,7 +108,7 @@ module Ransack
|
|
|
108
108
|
alias :g= :groupings=
|
|
109
109
|
|
|
110
110
|
def method_missing(method_id, *args)
|
|
111
|
-
method_name = method_id.to_s
|
|
111
|
+
method_name = method_id.to_s.dup
|
|
112
112
|
writer = method_name.sub!(/\=$/, ''.freeze)
|
|
113
113
|
if attribute_method?(method_name)
|
|
114
114
|
if writer
|
data/lib/ransack/nodes/node.rb
CHANGED
data/lib/ransack/nodes/sort.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Ransack
|
|
|
9
9
|
class << self
|
|
10
10
|
def extract(context, str)
|
|
11
11
|
return unless str
|
|
12
|
-
attr, direction = str.split(/\s+/,2)
|
|
12
|
+
attr, direction = str.split(/\s+/, 2)
|
|
13
13
|
self.new(context).build(name: attr, dir: direction)
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -31,8 +31,8 @@ module Ransack
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def name=(name)
|
|
34
|
-
@name = name
|
|
35
|
-
context.bind(self, name)
|
|
34
|
+
@name = context.ransackable_alias(name) || name
|
|
35
|
+
context.bind(self, @name)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def dir=(dir)
|
data/lib/ransack/nodes/value.rb
CHANGED
|
@@ -2,7 +2,7 @@ module Ransack
|
|
|
2
2
|
module Nodes
|
|
3
3
|
class Value < Node
|
|
4
4
|
attr_accessor :value
|
|
5
|
-
delegate :present?, :blank?, :
|
|
5
|
+
delegate :present?, :blank?, to: :value
|
|
6
6
|
|
|
7
7
|
def initialize(context, value = nil)
|
|
8
8
|
super(context)
|
|
@@ -26,7 +26,7 @@ module Ransack
|
|
|
26
26
|
case type
|
|
27
27
|
when :date
|
|
28
28
|
cast_to_date(value)
|
|
29
|
-
when :datetime, :timestamp, :time
|
|
29
|
+
when :datetime, :timestamp, :time, :timestamptz
|
|
30
30
|
cast_to_time(value)
|
|
31
31
|
when :boolean
|
|
32
32
|
cast_to_boolean(value)
|
|
@@ -50,7 +50,7 @@ module Ransack
|
|
|
50
50
|
y, m, d = *[val].flatten
|
|
51
51
|
m ||= 1
|
|
52
52
|
d ||= 1
|
|
53
|
-
Date.new(y,m,d) rescue nil
|
|
53
|
+
Date.new(y, m, d) rescue nil
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
data/lib/ransack/predicate.rb
CHANGED
data/lib/ransack/ransacker.rb
CHANGED
data/lib/ransack/search.rb
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
require 'ransack/nodes'
|
|
1
|
+
require 'ransack/nodes/bindable'
|
|
2
|
+
require 'ransack/nodes/node'
|
|
3
|
+
require 'ransack/nodes/attribute'
|
|
4
|
+
require 'ransack/nodes/value'
|
|
5
|
+
require 'ransack/nodes/condition'
|
|
6
|
+
require 'ransack/nodes/sort'
|
|
7
|
+
require 'ransack/nodes/grouping'
|
|
2
8
|
require 'ransack/context'
|
|
3
|
-
Ransack::Adapters.object_mapper.require_search
|
|
4
9
|
require 'ransack/naming'
|
|
5
10
|
|
|
6
11
|
module Ransack
|
|
@@ -9,15 +14,17 @@ module Ransack
|
|
|
9
14
|
|
|
10
15
|
attr_reader :base, :context
|
|
11
16
|
|
|
12
|
-
delegate :object, :klass, :
|
|
17
|
+
delegate :object, :klass, to: :context
|
|
13
18
|
delegate :new_grouping, :new_condition,
|
|
14
19
|
:build_grouping, :build_condition,
|
|
15
|
-
:translate, :
|
|
20
|
+
:translate, to: :base
|
|
16
21
|
|
|
17
22
|
def initialize(object, params = {}, options = {})
|
|
23
|
+
strip_whitespace = options.fetch(:strip_whitespace, Ransack.options[:strip_whitespace])
|
|
18
24
|
params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
|
|
19
25
|
if params.is_a? Hash
|
|
20
26
|
params = params.dup
|
|
27
|
+
params = params.transform_values { |v| v.is_a?(String) && strip_whitespace ? v.strip : v }
|
|
21
28
|
params.delete_if { |k, v| [*v].all?{ |i| i.blank? && i != false } }
|
|
22
29
|
else
|
|
23
30
|
params = {}
|
|
@@ -29,6 +36,7 @@ module Ransack
|
|
|
29
36
|
)
|
|
30
37
|
@scope_args = {}
|
|
31
38
|
@sorts ||= []
|
|
39
|
+
@ignore_unknown_conditions = options[:ignore_unknown_conditions] == false ? false : true
|
|
32
40
|
build(params.with_indifferent_access)
|
|
33
41
|
end
|
|
34
42
|
|
|
@@ -40,11 +48,11 @@ module Ransack
|
|
|
40
48
|
collapse_multiparameter_attributes!(params).each do |key, value|
|
|
41
49
|
if ['s'.freeze, 'sorts'.freeze].freeze.include?(key)
|
|
42
50
|
send("#{key}=", value)
|
|
43
|
-
elsif base.attribute_method?(key)
|
|
44
|
-
base.send("#{key}=", value)
|
|
45
51
|
elsif @context.ransackable_scope?(key, @context.object)
|
|
46
52
|
add_scope(key, value)
|
|
47
|
-
elsif
|
|
53
|
+
elsif base.attribute_method?(key)
|
|
54
|
+
base.send("#{key}=", value)
|
|
55
|
+
elsif !Ransack.options[:ignore_unknown_conditions] || !@ignore_unknown_conditions
|
|
48
56
|
raise ArgumentError, "Invalid search term #{key}"
|
|
49
57
|
end
|
|
50
58
|
end
|