ransack 2.3.0 → 4.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/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/codeql.yml +72 -0
- data/.github/workflows/cronjob.yml +102 -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 +128 -0
- data/.nojekyll +0 -0
- data/.rubocop.yml +47 -0
- data/CHANGELOG.md +228 -1
- data/CONTRIBUTING.md +47 -22
- 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 +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/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 +40 -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 +8790 -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 +23 -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 +59 -115
- 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 +109 -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 +83 -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
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,13 +45,132 @@ module Ransack
|
|
|
45
45
|
NOT_EQ_ALL = 'not_eq_all'.freeze
|
|
46
46
|
CONT = 'cont'.freeze
|
|
47
47
|
|
|
48
|
-
RAILS_5_1 = '5.1'.freeze
|
|
49
|
-
RAILS_5_2 = '5.2'.freeze
|
|
50
|
-
RAILS_5_2_0 = '5.2.0'.freeze
|
|
51
|
-
RAILS_6_0 = '6.0.0'.freeze
|
|
52
|
-
|
|
53
48
|
RANSACK_SLASH_SEARCHES = 'ransack/searches'.freeze
|
|
54
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
|
|
55
175
|
end
|
|
56
176
|
end
|
|
57
|
-
|
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
|
|
@@ -7,17 +7,11 @@ module ActionView::Helpers::Tags
|
|
|
7
7
|
class Base
|
|
8
8
|
private
|
|
9
9
|
if defined? ::ActiveRecord
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
object.send @method_name if object
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def value
|
|
16
|
-
if @allow_method_names_outside_object
|
|
17
|
-
object.send @method_name if object && object.respond_to?(@method_name, true)
|
|
18
|
-
else
|
|
19
|
-
object.send @method_name if object
|
|
20
|
-
end
|
|
10
|
+
def value
|
|
11
|
+
if @allow_method_names_outside_object
|
|
12
|
+
object.send @method_name if object && object.respond_to?(@method_name, true)
|
|
13
|
+
else
|
|
14
|
+
object.send @method_name if object
|
|
21
15
|
end
|
|
22
16
|
end
|
|
23
17
|
end
|
|
@@ -39,7 +33,7 @@ module Ransack
|
|
|
39
33
|
text = args.first
|
|
40
34
|
i18n = options[:i18n] || {}
|
|
41
35
|
text ||= object.translate(
|
|
42
|
-
method, i18n.reverse_merge(:
|
|
36
|
+
method, i18n.reverse_merge(include_associations: true)
|
|
43
37
|
) if object.respond_to? :translate
|
|
44
38
|
super(method, text, options, &block)
|
|
45
39
|
end
|
|
@@ -51,9 +45,9 @@ module Ransack
|
|
|
51
45
|
end
|
|
52
46
|
|
|
53
47
|
def attribute_select(options = nil, html_options = nil, action = nil)
|
|
54
|
-
options
|
|
55
|
-
html_options
|
|
56
|
-
action
|
|
48
|
+
options ||= {}
|
|
49
|
+
html_options ||= {}
|
|
50
|
+
action ||= Constants::SEARCH
|
|
57
51
|
default = options.delete(:default)
|
|
58
52
|
raise ArgumentError, formbuilder_error_message(
|
|
59
53
|
"#{action}_select") unless object.respond_to?(:context)
|
|
@@ -246,7 +240,7 @@ module Ransack
|
|
|
246
240
|
def get_attribute_element(action, base)
|
|
247
241
|
begin
|
|
248
242
|
[
|
|
249
|
-
Translate.association(base, :
|
|
243
|
+
Translate.association(base, context: object.context),
|
|
250
244
|
collection_for_base(action, base)
|
|
251
245
|
]
|
|
252
246
|
rescue UntraversableAssociationError
|
|
@@ -259,7 +253,7 @@ module Ransack
|
|
|
259
253
|
[
|
|
260
254
|
attr_from_base_and_column(base, c),
|
|
261
255
|
Translate.attribute(
|
|
262
|
-
attr_from_base_and_column(base, c), :
|
|
256
|
+
attr_from_base_and_column(base, c), context: object.context
|
|
263
257
|
)
|
|
264
258
|
]
|
|
265
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
|
+
sk:
|
|
2
|
+
ransack:
|
|
3
|
+
search: "vyhľadávanie"
|
|
4
|
+
predicate: "predikát"
|
|
5
|
+
and: "a"
|
|
6
|
+
or: "alebo"
|
|
7
|
+
any: "akýkoľvek"
|
|
8
|
+
all: "každý"
|
|
9
|
+
combinator: "kombinátor"
|
|
10
|
+
attribute: "atribút"
|
|
11
|
+
value: "hodnota"
|
|
12
|
+
condition: "podmienka"
|
|
13
|
+
sort: "poradie"
|
|
14
|
+
asc: "vzostupne"
|
|
15
|
+
desc: "zostupne"
|
|
16
|
+
predicates:
|
|
17
|
+
eq: "sa rovná"
|
|
18
|
+
eq_any: "sa rovná akémukoľvek"
|
|
19
|
+
eq_all: "sa rovná všetkým"
|
|
20
|
+
not_eq: "sa nerovná"
|
|
21
|
+
not_eq_any: "sa nerovná akémukoľvek"
|
|
22
|
+
not_eq_all: "sa nerovná všetkým"
|
|
23
|
+
matches: "zodpovedá"
|
|
24
|
+
matches_any: "zodpovedá akémukoľvek"
|
|
25
|
+
matches_all: "zodpovedá všetkým"
|
|
26
|
+
does_not_match: "nezodpovedá"
|
|
27
|
+
does_not_match_any: "nezodpovedá akémukoľvek"
|
|
28
|
+
does_not_match_all: "nezodpovedá všetkým"
|
|
29
|
+
lt: "menší ako"
|
|
30
|
+
lt_any: "menší ako akýkoľvek"
|
|
31
|
+
lt_all: "menší ako všetky"
|
|
32
|
+
lteq: "menší alebo rovný"
|
|
33
|
+
lteq_any: "menší alebo rovný akémukoľvek"
|
|
34
|
+
lteq_all: "menší alebo rovný všetkým"
|
|
35
|
+
gt: "väčší ako"
|
|
36
|
+
gt_any: "väčší ako akýkoľvek"
|
|
37
|
+
gt_all: "väčší ako všetky"
|
|
38
|
+
gteq: "väčší alebo rovný"
|
|
39
|
+
gteq_any: "väčší alebo rovný akémukoľvek"
|
|
40
|
+
gteq_all: "väčší alebo rovný všetkým"
|
|
41
|
+
in: "v"
|
|
42
|
+
in_any: "v akejkoľvek"
|
|
43
|
+
in_all: "vo všetkých"
|
|
44
|
+
not_in: "nie je v"
|
|
45
|
+
not_in_any: "nie je v akejkoľvek"
|
|
46
|
+
not_in_all: "nie je vo všetkých"
|
|
47
|
+
cont: "obsahuje"
|
|
48
|
+
cont_any: "obsahuje akúkoľvek"
|
|
49
|
+
cont_all: "obsahuje všetky"
|
|
50
|
+
not_cont: "neobsahuje"
|
|
51
|
+
not_cont_any: "neobsahuje akúkoľvek"
|
|
52
|
+
not_cont_all: "neobsahuje všetky"
|
|
53
|
+
start: "začína na"
|
|
54
|
+
start_any: "začína s akoukoľvek"
|
|
55
|
+
start_all: "začína so všetkými"
|
|
56
|
+
not_start: "nezačíná s"
|
|
57
|
+
not_start_any: "nezačíná s akoukoľvek"
|
|
58
|
+
not_start_all: "nezačíná so všetkými"
|
|
59
|
+
end: "končí s"
|
|
60
|
+
end_any: "končí s akoukoľvek"
|
|
61
|
+
end_all: "končí so všetkými"
|
|
62
|
+
not_end: "nekončí s"
|
|
63
|
+
not_end_any: "nekončí s akoukoľvek"
|
|
64
|
+
not_end_all: "nekončí so všetkými"
|
|
65
|
+
'true': "je pravdivé"
|
|
66
|
+
'false': "nie je pravdivé"
|
|
67
|
+
present: "je vyplnené"
|
|
68
|
+
blank: "je prázdne"
|
|
69
|
+
'null': "je null"
|
|
70
|
+
not_null: "nie je null"
|
|
@@ -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
|
|
@@ -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)
|