ransack 2.3.0 → 4.1.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/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 +263 -1
- data/CONTRIBUTING.md +51 -29
- data/Gemfile +24 -10
- data/README.md +49 -917
- 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_6.1_ruby_2/join_association.rb +70 -0
- data/{polyamorous/lib/polyamorous/activerecord_6.0_ruby_2 → lib/polyamorous/activerecord_6.1_ruby_2}/join_dependency.rb +33 -12
- data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +11 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_7.0_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_7.1_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_7.1_ruby_2/join_dependency.rb +1 -0
- data/lib/polyamorous/activerecord_7.1_ruby_2/reflection.rb +1 -0
- data/{polyamorous/lib → lib/polyamorous}/polyamorous.rb +3 -8
- data/lib/ransack/adapters/active_record/base.rb +83 -10
- data/lib/ransack/adapters/active_record/context.rb +61 -116
- data/lib/ransack/configuration.rb +53 -10
- data/lib/ransack/constants.rb +126 -7
- data/lib/ransack/context.rb +34 -5
- data/lib/ransack/helpers/form_builder.rb +11 -17
- data/lib/ransack/helpers/form_helper.rb +14 -5
- data/lib/ransack/helpers.rb +1 -1
- data/lib/ransack/locale/sk.yml +70 -0
- data/lib/ransack/locale/sv.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +3 -3
- data/lib/ransack/nodes/condition.rb +87 -8
- 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 +3 -2
- 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 +6 -10
- data/ransack.gemspec +9 -24
- 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 -17
- 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 +75 -2
- data/spec/ransack/search_spec.rb +239 -38
- data/spec/ransack/translate_spec.rb +1 -1
- data/spec/spec_helper.rb +9 -5
- data/spec/support/schema.rb +111 -12
- metadata +105 -195
- data/.travis.yml +0 -49
- data/lib/ransack/adapters/active_record/ransack/constants.rb +0 -116
- data/lib/ransack/adapters/active_record/ransack/context.rb +0 -60
- 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.0_ruby_2/join_association.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_5.0_ruby_2/join_dependency.rb +0 -2
- data/polyamorous/lib/polyamorous/activerecord_5.1_ruby_2/join_association.rb +0 -31
- data/polyamorous/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +0 -112
- data/polyamorous/lib/polyamorous/activerecord_5.2.0_ruby_2/join_association.rb +0 -31
- data/polyamorous/lib/polyamorous/activerecord_5.2.0_ruby_2/join_dependency.rb +0 -112
- data/polyamorous/lib/polyamorous/activerecord_5.2.0_ruby_2/reflection.rb +0 -12
- data/polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2/join_association.rb +0 -22
- data/polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2/join_dependency.rb +0 -81
- data/polyamorous/lib/polyamorous/activerecord_5.2.1_ruby_2/reflection.rb +0 -2
- 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 -35
- /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
|
@@ -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
|
|
@@ -255,6 +254,13 @@ module Ransack
|
|
|
255
254
|
end
|
|
256
255
|
end
|
|
257
256
|
|
|
257
|
+
def attr_value_for_attribute(attr)
|
|
258
|
+
return attr.attr if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
|
259
|
+
|
|
260
|
+
predicate.case_insensitive ? attr.attr.lower : attr.attr
|
|
261
|
+
rescue
|
|
262
|
+
attr.attr
|
|
263
|
+
end
|
|
258
264
|
|
|
259
265
|
def default_type
|
|
260
266
|
predicate.type || (attributes.first && attributes.first.type)
|
|
@@ -277,12 +283,85 @@ module Ransack
|
|
|
277
283
|
predicate.negative?
|
|
278
284
|
end
|
|
279
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
|
+
|
|
280
316
|
private
|
|
281
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
|
+
|
|
282
362
|
def valid_combinator?
|
|
283
363
|
attributes.size < 2 || Constants::AND_OR.include?(combinator)
|
|
284
364
|
end
|
|
285
|
-
|
|
286
365
|
end
|
|
287
366
|
end
|
|
288
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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Ransack
|
|
2
2
|
class Predicate
|
|
3
3
|
attr_reader :name, :arel_predicate, :type, :formatter, :validator,
|
|
4
|
-
:compound, :wants_array
|
|
4
|
+
:compound, :wants_array, :case_insensitive
|
|
5
5
|
|
|
6
6
|
class << self
|
|
7
7
|
|
|
@@ -10,7 +10,7 @@ module Ransack
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def named(name)
|
|
13
|
-
Ransack.predicates[name.to_s]
|
|
13
|
+
Ransack.predicates[(name || Ransack.options[:default_predicate]).to_s]
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def detect_and_strip_from_string!(str)
|
|
@@ -42,6 +42,7 @@ module Ransack
|
|
|
42
42
|
@compound = opts[:compound]
|
|
43
43
|
@wants_array = opts.fetch(:wants_array,
|
|
44
44
|
@compound || Constants::IN_NOT_IN.include?(@arel_predicate))
|
|
45
|
+
@case_insensitive = opts[:case_insensitive]
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
def eql?(other)
|
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
|
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,9 +49,8 @@ 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
|
-
I18n.translate(defaults.shift, options.merge(interpolations))
|
|
53
|
+
I18n.translate(defaults.shift, **options.merge(interpolations))
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def association(key, options = {})
|
|
@@ -66,8 +66,8 @@ module Ransack
|
|
|
66
66
|
[:"ransack.associations.#{i18n_key(context.klass)}.#{key}"]
|
|
67
67
|
end
|
|
68
68
|
defaults << context.traverse(key).model_name.human
|
|
69
|
-
options = { :
|
|
70
|
-
I18n.translate(defaults.shift, options)
|
|
69
|
+
options = { count: 1, default: defaults }
|
|
70
|
+
I18n.translate(defaults.shift, **options)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
private
|
|
@@ -83,7 +83,7 @@ module Ransack
|
|
|
83
83
|
options = { count: 1, default: defaults }
|
|
84
84
|
interpolations = build_interpolations(associated_class)
|
|
85
85
|
|
|
86
|
-
I18n.translate(defaults.shift, options.merge(interpolations))
|
|
86
|
+
I18n.translate(defaults.shift, **options.merge(interpolations))
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
def default_attribute_name
|
|
@@ -149,7 +149,7 @@ module Ransack
|
|
|
149
149
|
end
|
|
150
150
|
|
|
151
151
|
def i18n_key(klass)
|
|
152
|
-
|
|
152
|
+
klass.model_name.i18n_key
|
|
153
153
|
end
|
|
154
154
|
end
|
|
155
155
|
end
|
data/lib/ransack/version.rb
CHANGED
data/lib/ransack/visitor.rb
CHANGED
|
@@ -26,7 +26,14 @@ module Ransack
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def visit_and(object)
|
|
29
|
-
|
|
29
|
+
nodes = object.values.map { |o| accept(o) }.compact
|
|
30
|
+
return nil unless nodes.size > 0
|
|
31
|
+
|
|
32
|
+
if nodes.size > 1
|
|
33
|
+
Arel::Nodes::Grouping.new(Arel::Nodes::And.new(nodes))
|
|
34
|
+
else
|
|
35
|
+
nodes.first
|
|
36
|
+
end
|
|
30
37
|
end
|
|
31
38
|
|
|
32
39
|
def visit_or(object)
|
|
@@ -35,17 +42,46 @@ module Ransack
|
|
|
35
42
|
end
|
|
36
43
|
|
|
37
44
|
def quoted?(object)
|
|
38
|
-
|
|
45
|
+
case object
|
|
46
|
+
when Arel::Nodes::SqlLiteral, Bignum, Fixnum
|
|
47
|
+
false
|
|
48
|
+
else
|
|
49
|
+
true
|
|
50
|
+
end
|
|
39
51
|
end
|
|
40
52
|
|
|
41
53
|
def visit(object)
|
|
42
54
|
send(DISPATCH[object.class], object)
|
|
43
55
|
end
|
|
44
56
|
|
|
57
|
+
def visit_Ransack_Nodes_Sort(object)
|
|
58
|
+
if object.valid?
|
|
59
|
+
if object.attr.is_a?(Arel::Attributes::Attribute)
|
|
60
|
+
object.attr.send(object.dir)
|
|
61
|
+
else
|
|
62
|
+
ordered(object)
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
scope_name = :"sort_by_#{object.name}_#{object.dir}"
|
|
66
|
+
scope_name if object.context.object.respond_to?(scope_name)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
45
70
|
DISPATCH = Hash.new do |hash, klass|
|
|
46
71
|
hash[klass] = "visit_#{
|
|
47
72
|
klass.name.gsub(Constants::TWO_COLONS, Constants::UNDERSCORE)
|
|
48
73
|
}"
|
|
49
74
|
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def ordered(object)
|
|
79
|
+
case object.dir
|
|
80
|
+
when 'asc'.freeze
|
|
81
|
+
Arel::Nodes::Ascending.new(object.attr)
|
|
82
|
+
when 'desc'.freeze
|
|
83
|
+
Arel::Nodes::Descending.new(object.attr)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
50
86
|
end
|
|
51
87
|
end
|
data/lib/ransack.rb
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
require 'active_support/core_ext'
|
|
2
2
|
require 'ransack/configuration'
|
|
3
|
-
require '
|
|
4
|
-
require 'polyamorous'
|
|
5
|
-
|
|
6
|
-
Ransack::Adapters.object_mapper.require_constants
|
|
3
|
+
require 'polyamorous/polyamorous'
|
|
7
4
|
|
|
8
5
|
module Ransack
|
|
9
6
|
extend Configuration
|
|
10
|
-
class UntraversableAssociationError < StandardError; end
|
|
7
|
+
class UntraversableAssociationError < StandardError; end
|
|
11
8
|
end
|
|
12
9
|
|
|
13
10
|
Ransack.configure do |config|
|
|
14
11
|
Ransack::Constants::AREL_PREDICATES.each do |name|
|
|
15
|
-
config.add_predicate name, :
|
|
12
|
+
config.add_predicate name, arel_predicate: name
|
|
16
13
|
end
|
|
17
14
|
Ransack::Constants::DERIVED_PREDICATES.each do |args|
|
|
18
15
|
config.add_predicate(*args)
|
|
@@ -21,12 +18,11 @@ end
|
|
|
21
18
|
|
|
22
19
|
require 'ransack/search'
|
|
23
20
|
require 'ransack/ransacker'
|
|
24
|
-
require 'ransack/helpers'
|
|
25
|
-
require 'action_controller'
|
|
26
21
|
require 'ransack/translate'
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
require 'ransack/active_record'
|
|
23
|
+
require 'ransack/context'
|
|
29
24
|
|
|
30
25
|
ActiveSupport.on_load(:action_controller) do
|
|
26
|
+
require 'ransack/helpers'
|
|
31
27
|
ActionController::Base.helper Ransack::Helpers::FormHelper
|
|
32
28
|
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", "David Rodríguez"]
|
|
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
|
-
s.summary = %q{Object-based searching for Active Record
|
|
13
|
+
s.summary = %q{Object-based searching for Active Record.}
|
|
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 = '>=
|
|
15
|
+
s.required_ruby_version = '>= 3.0'
|
|
15
16
|
s.license = 'MIT'
|
|
16
17
|
|
|
17
|
-
s.add_dependency '
|
|
18
|
-
s.add_dependency '
|
|
19
|
-
s.add_dependency 'activesupport', '>= 5.0'
|
|
18
|
+
s.add_dependency 'activerecord', '>= 6.1.5'
|
|
19
|
+
s.add_dependency 'activesupport', '>= 6.1.5'
|
|
20
20
|
s.add_dependency 'i18n'
|
|
21
|
-
s.add_dependency 'polyamorous', Ransack::VERSION.to_s
|
|
22
|
-
s.add_development_dependency 'rspec', '~> 3'
|
|
23
|
-
s.add_development_dependency 'machinist', '~> 1.0.6'
|
|
24
|
-
s.add_development_dependency 'faker', '~> 0.9.5'
|
|
25
|
-
s.add_development_dependency 'sqlite3', ::Gem::Version.new(ENV['RAILS'].gsub(/^v/, '')) >= ::Gem::Version.new('6-0-stable') ? '~> 1.4.1' : '~> 1.3.3'
|
|
26
|
-
s.add_development_dependency 'pg', '~> 0.21'
|
|
27
|
-
s.add_development_dependency 'mysql2', '0.3.20'
|
|
28
|
-
s.add_development_dependency 'pry', '0.10'
|
|
29
|
-
s.add_development_dependency 'byebug'
|
|
30
21
|
|
|
31
22
|
s.files = `git ls-files`.split("\n")
|
|
32
|
-
|
|
33
|
-
s.
|
|
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
|
data/spec/blueprints/articles.rb
CHANGED
data/spec/blueprints/comments.rb
CHANGED
data/spec/blueprints/notes.rb
CHANGED
data/spec/blueprints/tags.rb
CHANGED
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,23 +3,8 @@ module PolyamorousHelper
|
|
|
3
3
|
Polyamorous::JoinAssociation.new reflection, children, klass
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Polyamorous::JoinDependency.new klass, klass.arel_table, associations, Polyamorous::InnerJoin
|
|
9
|
-
end
|
|
10
|
-
elsif ActiveRecord.version > ::Gem::Version.new("5.2.0")
|
|
11
|
-
def new_join_dependency(klass, associations = {})
|
|
12
|
-
Polyamorous::JoinDependency.new klass, klass.arel_table, associations
|
|
13
|
-
end
|
|
14
|
-
elsif ActiveRecord.version == ::Gem::Version.new("5.2.0")
|
|
15
|
-
def new_join_dependency(klass, associations = {})
|
|
16
|
-
alias_tracker = ::ActiveRecord::Associations::AliasTracker.create(klass.connection, klass.table_name, [])
|
|
17
|
-
Polyamorous::JoinDependency.new klass, klass.arel_table, associations, alias_tracker
|
|
18
|
-
end
|
|
19
|
-
else
|
|
20
|
-
def new_join_dependency(klass, associations = {})
|
|
21
|
-
Polyamorous::JoinDependency.new klass, associations, []
|
|
22
|
-
end
|
|
6
|
+
def new_join_dependency(klass, associations = {})
|
|
7
|
+
Polyamorous::JoinDependency.new klass, klass.arel_table, associations, Polyamorous::InnerJoin
|
|
23
8
|
end
|
|
24
9
|
|
|
25
10
|
def new_join(name, type = Polyamorous::InnerJoin, klass = nil)
|
|
@@ -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
|
|
@@ -10,7 +10,9 @@ module Polyamorous
|
|
|
10
10
|
new_join_association(reflection, parent.children, Article)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
subject { new_join_association(reflection, parent.children, Person) }
|
|
14
|
+
|
|
15
|
+
it 'leaves the original reflection intact for thread safety' do
|
|
14
16
|
reflection.instance_variable_set(:@klass, Article)
|
|
15
17
|
join_association
|
|
16
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
|