ransack 1.7.0 → 2.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +3 -0
- data/.github/SECURITY.md +12 -0
- data/.github/workflows/test.yml +120 -0
- data/.gitignore +3 -0
- data/CHANGELOG.md +463 -27
- data/CONTRIBUTING.md +52 -22
- data/Gemfile +24 -24
- data/README.md +453 -126
- data/Rakefile +6 -25
- data/lib/polyamorous/activerecord_5.2_ruby_2/join_association.rb +24 -0
- data/lib/polyamorous/activerecord_5.2_ruby_2/join_dependency.rb +79 -0
- data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +11 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +1 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +80 -0
- data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +74 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +93 -0
- data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +1 -0
- data/lib/polyamorous/join.rb +70 -0
- data/lib/polyamorous/polyamorous.rb +24 -0
- data/lib/polyamorous/swapping_reflection_class.rb +11 -0
- data/lib/polyamorous/tree_node.rb +7 -0
- data/lib/ransack/adapters/active_record/base.rb +27 -2
- data/lib/ransack/adapters/active_record/context.rb +213 -139
- data/lib/ransack/adapters/active_record/ransack/constants.rb +70 -55
- data/lib/ransack/adapters/active_record/ransack/context.rb +10 -18
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +42 -32
- data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -5
- data/lib/ransack/adapters/active_record/ransack/visitor.rb +23 -0
- data/lib/ransack/adapters/active_record.rb +11 -10
- data/lib/ransack/adapters.rb +45 -23
- data/lib/ransack/configuration.rb +107 -4
- data/lib/ransack/constants.rb +13 -26
- data/lib/ransack/context.rb +45 -33
- data/lib/ransack/helpers/form_builder.rb +21 -12
- data/lib/ransack/helpers/form_helper.rb +75 -70
- data/lib/ransack/locale/ar.yml +70 -0
- data/lib/ransack/locale/az.yml +70 -0
- data/lib/ransack/locale/bg.yml +70 -0
- data/lib/ransack/locale/ca.yml +70 -0
- data/lib/ransack/locale/da.yml +70 -0
- data/lib/ransack/locale/el.yml +70 -0
- data/lib/ransack/locale/es.yml +22 -22
- data/lib/ransack/locale/fa.yml +70 -0
- data/lib/ransack/locale/fi.yml +71 -0
- data/lib/ransack/locale/id.yml +70 -0
- data/lib/ransack/locale/it.yml +70 -0
- data/lib/ransack/locale/ja.yml +70 -0
- data/lib/ransack/locale/nl.yml +4 -4
- data/lib/ransack/locale/pt-BR.yml +70 -0
- data/lib/ransack/locale/ru.yml +70 -0
- data/lib/ransack/locale/sk.yml +70 -0
- data/lib/ransack/locale/tr.yml +70 -0
- data/lib/ransack/locale/{zh.yml → zh-CN.yml} +13 -13
- data/lib/ransack/locale/zh-TW.yml +70 -0
- data/lib/ransack/nodes/attribute.rb +5 -2
- data/lib/ransack/nodes/bindable.rb +18 -6
- data/lib/ransack/nodes/condition.rb +85 -28
- data/lib/ransack/nodes/grouping.rb +17 -11
- data/lib/ransack/nodes/sort.rb +9 -5
- data/lib/ransack/nodes/value.rb +74 -68
- data/lib/ransack/nodes.rb +1 -1
- data/lib/ransack/predicate.rb +17 -20
- data/lib/ransack/search.rb +17 -8
- data/lib/ransack/translate.rb +115 -115
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +1 -12
- data/lib/ransack.rb +9 -9
- data/logo/ransack-h.png +0 -0
- data/logo/ransack-h.svg +34 -0
- data/logo/ransack-v.png +0 -0
- data/logo/ransack-v.svg +34 -0
- data/logo/ransack.png +0 -0
- data/logo/ransack.svg +21 -0
- data/ransack.gemspec +7 -24
- data/spec/console.rb +4 -0
- data/spec/helpers/polyamorous_helper.rb +19 -0
- data/spec/polyamorous/join_association_spec.rb +35 -0
- data/spec/polyamorous/join_dependency_spec.rb +97 -0
- data/spec/polyamorous/join_spec.rb +19 -0
- data/spec/ransack/adapters/active_record/base_spec.rb +370 -75
- data/spec/ransack/adapters/active_record/context_spec.rb +72 -34
- data/spec/ransack/configuration_spec.rb +97 -14
- data/spec/ransack/helpers/form_builder_spec.rb +2 -11
- data/spec/ransack/helpers/form_helper_spec.rb +481 -113
- data/spec/ransack/nodes/condition_spec.rb +24 -0
- data/spec/ransack/nodes/grouping_spec.rb +56 -0
- data/spec/ransack/predicate_spec.rb +79 -5
- data/spec/ransack/search_spec.rb +207 -81
- data/spec/spec_helper.rb +8 -0
- data/spec/support/schema.rb +100 -42
- metadata +57 -184
- data/.travis.yml +0 -69
- data/lib/ransack/adapters/active_record/3.0/compat.rb +0 -179
- data/lib/ransack/adapters/active_record/3.0/context.rb +0 -201
- data/lib/ransack/adapters/active_record/3.1/context.rb +0 -215
- data/lib/ransack/adapters/active_record/3.2/context.rb +0 -44
- data/lib/ransack/adapters/active_record/compat.rb +0 -14
- data/lib/ransack/adapters/mongoid/3.2/.gitkeep +0 -0
- data/lib/ransack/adapters/mongoid/attributes/attribute.rb +0 -37
- data/lib/ransack/adapters/mongoid/attributes/order_predications.rb +0 -17
- data/lib/ransack/adapters/mongoid/attributes/predications.rb +0 -141
- data/lib/ransack/adapters/mongoid/base.rb +0 -130
- data/lib/ransack/adapters/mongoid/context.rb +0 -208
- data/lib/ransack/adapters/mongoid/inquiry_hash.rb +0 -23
- data/lib/ransack/adapters/mongoid/ransack/constants.rb +0 -88
- data/lib/ransack/adapters/mongoid/ransack/context.rb +0 -60
- data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +0 -27
- data/lib/ransack/adapters/mongoid/ransack/translate.rb +0 -13
- data/lib/ransack/adapters/mongoid/ransack/visitor.rb +0 -24
- data/lib/ransack/adapters/mongoid/table.rb +0 -35
- data/lib/ransack/adapters/mongoid.rb +0 -13
- data/spec/mongoid/adapters/mongoid/base_spec.rb +0 -276
- data/spec/mongoid/adapters/mongoid/context_spec.rb +0 -56
- data/spec/mongoid/configuration_spec.rb +0 -102
- data/spec/mongoid/dependencies_spec.rb +0 -8
- data/spec/mongoid/helpers/ransack_helper.rb +0 -11
- data/spec/mongoid/nodes/condition_spec.rb +0 -34
- data/spec/mongoid/nodes/grouping_spec.rb +0 -13
- data/spec/mongoid/predicate_spec.rb +0 -155
- data/spec/mongoid/search_spec.rb +0 -446
- data/spec/mongoid/support/mongoid.yml +0 -6
- data/spec/mongoid/support/schema.rb +0 -128
- data/spec/mongoid/translate_spec.rb +0 -14
- data/spec/mongoid_spec_helper.rb +0 -59
- data/spec/ransack/dependencies_spec.rb +0 -12
@@ -3,53 +3,63 @@ module Ransack
|
|
3
3
|
class Condition
|
4
4
|
|
5
5
|
def arel_predicate
|
6
|
-
|
6
|
+
attributes.map { |attribute|
|
7
|
+
association = attribute.parent
|
8
|
+
if negative? && attribute.associated_collection?
|
9
|
+
query = context.build_correlated_subquery(association)
|
10
|
+
context.remove_association(association)
|
11
|
+
if self.predicate_name == 'not_null' && self.value
|
12
|
+
query.where(format_predicate(attribute))
|
13
|
+
Arel::Nodes::In.new(context.primary_key, Arel.sql(query.to_sql))
|
14
|
+
else
|
15
|
+
query.where(format_predicate(attribute).not)
|
16
|
+
Arel::Nodes::NotIn.new(context.primary_key, Arel.sql(query.to_sql))
|
17
|
+
end
|
18
|
+
else
|
19
|
+
format_predicate(attribute)
|
20
|
+
end
|
21
|
+
}.reduce(combinator_method)
|
7
22
|
end
|
8
23
|
|
9
24
|
private
|
10
25
|
|
11
|
-
def
|
12
|
-
|
13
|
-
a.attr.send(
|
14
|
-
arel_predicate_for_attribute(a), formatted_values_for_attribute(a)
|
15
|
-
)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def arel_predicate_for(predicates)
|
20
|
-
if predicates.size > 1
|
21
|
-
combinator_for(predicates)
|
22
|
-
else
|
23
|
-
format_predicate(predicates.first)
|
24
|
-
end
|
26
|
+
def combinator_method
|
27
|
+
combinator === Constants::OR ? :or : :and
|
25
28
|
end
|
26
29
|
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
predicates.inject(&:or)
|
32
|
-
end
|
33
|
-
end
|
30
|
+
def format_predicate(attribute)
|
31
|
+
arel_pred = arel_predicate_for_attribute(attribute)
|
32
|
+
arel_values = formatted_values_for_attribute(attribute)
|
33
|
+
predicate = attr_value_for_attribute(attribute).public_send(arel_pred, arel_values)
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
predicate.right[0] = format_values_for(predicate.right[0])
|
35
|
+
if in_predicate?(predicate)
|
36
|
+
predicate.right = predicate.right.map do |pr|
|
37
|
+
casted_array?(pr) ? format_values_for(pr) : pr
|
39
38
|
end
|
40
39
|
end
|
40
|
+
|
41
|
+
predicate
|
41
42
|
end
|
42
43
|
|
43
|
-
def
|
44
|
+
def in_predicate?(predicate)
|
44
45
|
return unless defined?(Arel::Nodes::Casted)
|
45
|
-
predicate.class == Arel::Nodes::In
|
46
|
-
|
47
|
-
|
46
|
+
predicate.class == Arel::Nodes::In || predicate.class == Arel::Nodes::NotIn
|
47
|
+
end
|
48
|
+
|
49
|
+
def casted_array?(predicate)
|
50
|
+
(predicate.respond_to?(:value) && predicate.value.is_a?(Array)) || # Rails 6.1
|
51
|
+
(predicate.respond_to?(:val) && predicate.val.is_a?(Array)) # Rails 5.2, 6.0
|
48
52
|
end
|
49
53
|
|
50
54
|
def format_values_for(predicate)
|
51
|
-
predicate.
|
52
|
-
|
55
|
+
value = if predicate.respond_to?(:value)
|
56
|
+
predicate.value # Rails 6.1
|
57
|
+
else
|
58
|
+
predicate.val # Rails 5.2, 6.0
|
59
|
+
end
|
60
|
+
|
61
|
+
value.map do |val|
|
62
|
+
val.is_a?(String) ? Arel::Nodes.build_quoted(val) : val
|
53
63
|
end
|
54
64
|
end
|
55
65
|
|
@@ -2,11 +2,7 @@ module Ransack
|
|
2
2
|
module Translate
|
3
3
|
|
4
4
|
def self.i18n_key(klass)
|
5
|
-
|
6
|
-
klass.model_name.i18n_key.to_s.tr('.'.freeze, '/'.freeze)
|
7
|
-
else
|
8
|
-
klass.model_name.i18n_key.to_s.freeze
|
9
|
-
end
|
5
|
+
klass.model_name.i18n_key
|
10
6
|
end
|
11
7
|
end
|
12
8
|
end
|
@@ -20,5 +20,28 @@ module Ransack
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
def visit_Ransack_Nodes_Sort(object)
|
24
|
+
if object.valid?
|
25
|
+
if object.attr.is_a?(Arel::Attributes::Attribute)
|
26
|
+
object.attr.send(object.dir)
|
27
|
+
else
|
28
|
+
ordered(object)
|
29
|
+
end
|
30
|
+
else
|
31
|
+
scope_name = :"sort_by_#{object.name}_#{object.dir}"
|
32
|
+
scope_name if object.context.object.respond_to?(scope_name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def ordered(object)
|
39
|
+
case object.dir
|
40
|
+
when 'asc'.freeze
|
41
|
+
Arel::Nodes::Ascending.new(object.attr)
|
42
|
+
when 'desc'.freeze
|
43
|
+
Arel::Nodes::Descending.new(object.attr)
|
44
|
+
end
|
45
|
+
end
|
23
46
|
end
|
24
47
|
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
require 'ransack/adapters/active_record/base'
|
2
|
-
ActiveRecord::Base.extend Ransack::Adapters::ActiveRecord::Base
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
ActiveSupport.on_load(:active_record) do
|
4
|
+
extend Ransack::Adapters::ActiveRecord::Base
|
5
|
+
|
6
|
+
Ransack::SUPPORTS_ATTRIBUTE_ALIAS =
|
7
|
+
begin
|
8
|
+
ActiveRecord::Base.respond_to?(:attribute_aliases)
|
9
|
+
rescue NameError
|
10
|
+
false
|
11
|
+
end
|
13
12
|
end
|
13
|
+
|
14
|
+
require 'ransack/adapters/active_record/context'
|
data/lib/ransack/adapters.rb
CHANGED
@@ -1,42 +1,64 @@
|
|
1
1
|
module Ransack
|
2
2
|
module Adapters
|
3
3
|
|
4
|
-
def self.
|
5
|
-
@
|
6
|
-
:active_record => defined?(::ActiveRecord::Base),
|
7
|
-
:mongoid => defined?(::Mongoid) && !defined?(::ActiveRecord::Base)
|
8
|
-
}
|
4
|
+
def self.object_mapper
|
5
|
+
@object_mapper ||= instantiate_object_mapper
|
9
6
|
end
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
|
8
|
+
def self.instantiate_object_mapper
|
9
|
+
if defined?(::ActiveRecord::Base)
|
10
|
+
ActiveRecordAdapter.new
|
11
|
+
elsif defined?(::Mongoid)
|
12
|
+
MongoidAdapter.new
|
13
|
+
else
|
14
|
+
raise "Unsupported adapter"
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
class ActiveRecordAdapter
|
19
|
+
def require_constants
|
20
|
+
require 'ransack/adapters/active_record/ransack/constants'
|
21
|
+
end
|
22
|
+
|
23
|
+
def require_adapter
|
17
24
|
require 'ransack/adapters/active_record/ransack/translate'
|
18
25
|
require 'ransack/adapters/active_record'
|
19
26
|
end
|
20
27
|
|
21
|
-
|
28
|
+
def require_context
|
29
|
+
require 'ransack/adapters/active_record/ransack/visitor'
|
30
|
+
end
|
31
|
+
|
32
|
+
def require_nodes
|
33
|
+
require 'ransack/adapters/active_record/ransack/nodes/condition'
|
34
|
+
end
|
35
|
+
|
36
|
+
def require_search
|
37
|
+
require 'ransack/adapters/active_record/ransack/context'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class MongoidAdapter
|
42
|
+
def require_constants
|
43
|
+
require 'ransack/adapters/mongoid/ransack/constants'
|
44
|
+
end
|
45
|
+
|
46
|
+
def require_adapter
|
22
47
|
require 'ransack/adapters/mongoid/ransack/translate'
|
23
48
|
require 'ransack/adapters/mongoid'
|
24
49
|
end
|
25
|
-
end
|
26
50
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
51
|
+
def require_context
|
52
|
+
require 'ransack/adapters/mongoid/ransack/visitor'
|
53
|
+
end
|
31
54
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
55
|
+
def require_nodes
|
56
|
+
require 'ransack/adapters/mongoid/ransack/nodes/condition'
|
57
|
+
end
|
36
58
|
|
37
|
-
|
38
|
-
|
39
|
-
|
59
|
+
def require_search
|
60
|
+
require 'ransack/adapters/mongoid/ransack/context'
|
61
|
+
end
|
40
62
|
end
|
41
63
|
end
|
42
64
|
end
|
@@ -5,10 +5,36 @@ module Ransack
|
|
5
5
|
module Configuration
|
6
6
|
|
7
7
|
mattr_accessor :predicates, :options
|
8
|
-
|
8
|
+
|
9
|
+
class PredicateCollection
|
10
|
+
attr_reader :sorted_names_with_underscores
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@collection = {}
|
14
|
+
@sorted_names_with_underscores = []
|
15
|
+
end
|
16
|
+
|
17
|
+
delegate :[], :keys, :has_key?, to: :@collection
|
18
|
+
|
19
|
+
def []=(key, value)
|
20
|
+
@sorted_names_with_underscores << [key, '_' + key]
|
21
|
+
@sorted_names_with_underscores.sort! { |(a, _), (b, _)| b.length <=> a.length }
|
22
|
+
|
23
|
+
@collection[key] = value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
self.predicates = PredicateCollection.new
|
28
|
+
|
9
29
|
self.options = {
|
10
30
|
:search_key => :q,
|
11
|
-
:ignore_unknown_conditions => true
|
31
|
+
:ignore_unknown_conditions => true,
|
32
|
+
:hide_sort_order_indicators => false,
|
33
|
+
:up_arrow => '▼'.freeze,
|
34
|
+
:down_arrow => '▲'.freeze,
|
35
|
+
:default_arrow => nil,
|
36
|
+
:sanitize_scope_args => true,
|
37
|
+
:postgres_fields_sort_option => nil
|
12
38
|
}
|
13
39
|
|
14
40
|
def configure
|
@@ -61,12 +87,89 @@ module Ransack
|
|
61
87
|
self.options[:search_key] = name
|
62
88
|
end
|
63
89
|
|
64
|
-
#
|
65
|
-
# into a search.
|
90
|
+
# By default Ransack ignores errors if an unknown predicate, condition or
|
91
|
+
# attribute is passed into a search. The default may be overridden in an
|
92
|
+
# initializer file like `config/initializers/ransack.rb` as follows:
|
93
|
+
#
|
94
|
+
# Ransack.configure do |config|
|
95
|
+
# # Raise if an unknown predicate, condition or attribute is passed
|
96
|
+
# config.ignore_unknown_conditions = false
|
97
|
+
# end
|
98
|
+
#
|
66
99
|
def ignore_unknown_conditions=(boolean)
|
67
100
|
self.options[:ignore_unknown_conditions] = boolean
|
68
101
|
end
|
69
102
|
|
103
|
+
# By default, Ransack displays sort order indicator arrows with HTML codes:
|
104
|
+
#
|
105
|
+
# up_arrow: '▼'
|
106
|
+
# down_arrow: '▲'
|
107
|
+
#
|
108
|
+
# There is also a default arrow which is displayed if a column is not sorted.
|
109
|
+
# By default this is nil so nothing will be displayed.
|
110
|
+
#
|
111
|
+
# Any of the defaults may be globally overridden in an initializer file
|
112
|
+
# like `config/initializers/ransack.rb` as follows:
|
113
|
+
#
|
114
|
+
# Ransack.configure do |config|
|
115
|
+
# # Globally set the up arrow to an icon, and the down and default arrows to unicode.
|
116
|
+
# config.custom_arrows = {
|
117
|
+
# up_arrow: '<i class="fa fa-long-arrow-up"></i>',
|
118
|
+
# down_arrow: 'U+02193',
|
119
|
+
# default_arrow: 'U+11047'
|
120
|
+
# }
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
def custom_arrows=(opts = {})
|
124
|
+
self.options[:up_arrow] = opts[:up_arrow].freeze if opts[:up_arrow]
|
125
|
+
self.options[:down_arrow] = opts[:down_arrow].freeze if opts[:down_arrow]
|
126
|
+
self.options[:default_arrow] = opts[:default_arrow].freeze if opts[:default_arrow]
|
127
|
+
end
|
128
|
+
|
129
|
+
# Ransack sanitizes many values in your custom scopes into booleans.
|
130
|
+
# [1, '1', 't', 'T', 'true', 'TRUE'] all evaluate to true.
|
131
|
+
# [0, '0', 'f', 'F', 'false', 'FALSE'] all evaluate to false.
|
132
|
+
#
|
133
|
+
# This default may be globally overridden in an initializer file like
|
134
|
+
# `config/initializers/ransack.rb` as follows:
|
135
|
+
#
|
136
|
+
# Ransack.configure do |config|
|
137
|
+
# # Accept my custom scope values as what they are.
|
138
|
+
# config.sanitize_custom_scope_booleans = false
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
def sanitize_custom_scope_booleans=(boolean)
|
142
|
+
self.options[:sanitize_scope_args] = boolean
|
143
|
+
end
|
144
|
+
|
145
|
+
# The `NULLS FIRST` and `NULLS LAST` options can be used to determine
|
146
|
+
# whether nulls appear before or after non-null values in the sort ordering.
|
147
|
+
#
|
148
|
+
# User may want to configure it like this:
|
149
|
+
#
|
150
|
+
# Ransack.configure do |c|
|
151
|
+
# c.postgres_fields_sort_option = :nulls_first # or :nulls_last
|
152
|
+
# end
|
153
|
+
#
|
154
|
+
# See this feature: https://www.postgresql.org/docs/13/queries-order.html
|
155
|
+
#
|
156
|
+
def postgres_fields_sort_option=(setting)
|
157
|
+
self.options[:postgres_fields_sort_option] = setting
|
158
|
+
end
|
159
|
+
|
160
|
+
# By default, Ransack displays sort order indicator arrows in sort links.
|
161
|
+
# The default may be globally overridden in an initializer file like
|
162
|
+
# `config/initializers/ransack.rb` as follows:
|
163
|
+
#
|
164
|
+
# Ransack.configure do |config|
|
165
|
+
# # Hide sort link order indicators globally across the application
|
166
|
+
# config.hide_sort_order_indicators = true
|
167
|
+
# end
|
168
|
+
#
|
169
|
+
def hide_sort_order_indicators=(boolean)
|
170
|
+
self.options[:hide_sort_order_indicators] = boolean
|
171
|
+
end
|
172
|
+
|
70
173
|
def arel_predicate_with_suffix(arel_predicate, suffix)
|
71
174
|
if arel_predicate === Proc
|
72
175
|
proc { |v| "#{arel_predicate.call(v)}#{suffix}" }
|
data/lib/ransack/constants.rb
CHANGED
@@ -1,19 +1,7 @@
|
|
1
1
|
module Ransack
|
2
2
|
module Constants
|
3
|
-
ASC = 'asc'.freeze
|
4
|
-
DESC = 'desc'.freeze
|
5
|
-
ASC_DESC = [ASC, DESC].freeze
|
6
|
-
|
7
|
-
ASC_ARROW = '▲'.freeze
|
8
|
-
DESC_ARROW = '▼'.freeze
|
9
|
-
|
10
3
|
OR = 'or'.freeze
|
11
4
|
AND = 'and'.freeze
|
12
|
-
SPACED_AND = ' AND '.freeze
|
13
|
-
|
14
|
-
SORT = 'sort'.freeze
|
15
|
-
SORT_LINK = 'sort_link'.freeze
|
16
|
-
SORT_DIRECTION = 'sort_direction'.freeze
|
17
5
|
|
18
6
|
CAP_SEARCH = 'Search'.freeze
|
19
7
|
SEARCH = 'search'.freeze
|
@@ -23,17 +11,12 @@ module Ransack
|
|
23
11
|
ATTRIBUTES = 'attributes'.freeze
|
24
12
|
COMBINATOR = 'combinator'.freeze
|
25
13
|
|
26
|
-
SPACE = ' '.freeze
|
27
|
-
COMMA_SPACE = ', '.freeze
|
28
|
-
COLON_SPACE = ': '.freeze
|
29
14
|
TWO_COLONS = '::'.freeze
|
30
15
|
UNDERSCORE = '_'.freeze
|
31
16
|
LEFT_PARENTHESIS = '('.freeze
|
32
17
|
Q = 'q'.freeze
|
33
18
|
I = 'i'.freeze
|
34
|
-
NON_BREAKING_SPACE = ' '.freeze
|
35
19
|
DOT_ASTERIX = '.*'.freeze
|
36
|
-
EMPTY = ''.freeze
|
37
20
|
|
38
21
|
STRING_JOIN = 'string_join'.freeze
|
39
22
|
ASSOCIATION_JOIN = 'association_join'.freeze
|
@@ -44,14 +27,17 @@ module Ransack
|
|
44
27
|
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set
|
45
28
|
BOOLEAN_VALUES = (TRUE_VALUES + FALSE_VALUES).freeze
|
46
29
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
30
|
+
AND_OR = ['and'.freeze, 'or'.freeze].freeze
|
31
|
+
IN_NOT_IN = ['in'.freeze, 'not_in'.freeze].freeze
|
32
|
+
SUFFIXES = ['_any'.freeze, '_all'.freeze].freeze
|
33
|
+
AREL_PREDICATES = [
|
34
|
+
'eq'.freeze, 'not_eq'.freeze,
|
35
|
+
'matches'.freeze, 'does_not_match'.freeze,
|
36
|
+
'lt'.freeze, 'lteq'.freeze,
|
37
|
+
'gt'.freeze, 'gteq'.freeze,
|
38
|
+
'in'.freeze, 'not_in'.freeze
|
39
|
+
].freeze
|
40
|
+
A_S_I = ['a'.freeze, 's'.freeze, 'i'.freeze].freeze
|
55
41
|
|
56
42
|
EQ = 'eq'.freeze
|
57
43
|
NOT_EQ = 'not_eq'.freeze
|
@@ -59,7 +45,8 @@ module Ransack
|
|
59
45
|
NOT_EQ_ALL = 'not_eq_all'.freeze
|
60
46
|
CONT = 'cont'.freeze
|
61
47
|
|
62
|
-
|
48
|
+
RAILS_6_0 = '6.0.0'.freeze
|
49
|
+
RAILS_6_1_ALPHA = '6.1.0.alpha'.freeze
|
63
50
|
|
64
51
|
RANSACK_SLASH_SEARCHES = 'ransack/searches'.freeze
|
65
52
|
RANSACK_SLASH_SEARCHES_SLASH_SEARCH = 'ransack/searches/search'.freeze
|
data/lib/ransack/context.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'ransack/visitor'
|
2
|
-
Ransack::Adapters.require_context
|
2
|
+
Ransack::Adapters.object_mapper.require_context
|
3
3
|
|
4
4
|
module Ransack
|
5
5
|
class Context
|
@@ -17,9 +17,12 @@ module Ransack
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def for(object, options = {})
|
20
|
-
context =
|
21
|
-
|
22
|
-
|
20
|
+
context =
|
21
|
+
if Class === object
|
22
|
+
for_class(object, options)
|
23
|
+
else
|
24
|
+
for_object(object, options)
|
25
|
+
end
|
23
26
|
context or raise ArgumentError,
|
24
27
|
"Don't know what context to use for #{object}"
|
25
28
|
end
|
@@ -37,7 +40,7 @@ module Ransack
|
|
37
40
|
# Convert a string representing a chain of associations and an attribute
|
38
41
|
# into the attribute itself
|
39
42
|
def contextualize(str)
|
40
|
-
parent, attr_name =
|
43
|
+
parent, attr_name = bind_pair_for(str)
|
41
44
|
table_for(parent)[attr_name]
|
42
45
|
end
|
43
46
|
|
@@ -55,32 +58,34 @@ module Ransack
|
|
55
58
|
end
|
56
59
|
|
57
60
|
def bind(object, str)
|
58
|
-
|
61
|
+
return nil unless str
|
62
|
+
object.parent, object.attr_name = bind_pair_for(str)
|
59
63
|
end
|
60
64
|
|
61
65
|
def traverse(str, base = @base)
|
62
|
-
str ||=
|
63
|
-
|
64
|
-
|
66
|
+
str ||= ''.freeze
|
67
|
+
segments = str.split(Constants::UNDERSCORE)
|
68
|
+
unless segments.empty?
|
65
69
|
remainder = []
|
66
70
|
found_assoc = nil
|
67
|
-
|
71
|
+
until found_assoc || segments.empty?
|
68
72
|
# Strip the _of_Model_type text from the association name, but hold
|
69
73
|
# onto it in klass, for use as the next base
|
70
74
|
assoc, klass = unpolymorphize_association(
|
71
75
|
segments.join(Constants::UNDERSCORE)
|
72
|
-
|
76
|
+
)
|
73
77
|
if found_assoc = get_association(assoc, base)
|
74
78
|
base = traverse(
|
75
|
-
remainder.join(
|
76
|
-
|
77
|
-
)
|
79
|
+
remainder.join(Constants::UNDERSCORE), klass || found_assoc.klass
|
80
|
+
)
|
78
81
|
end
|
79
82
|
|
80
83
|
remainder.unshift segments.pop
|
81
84
|
end
|
82
|
-
|
83
|
-
|
85
|
+
unless found_assoc
|
86
|
+
raise(UntraversableAssociationError,
|
87
|
+
"No association matches #{str}")
|
88
|
+
end
|
84
89
|
end
|
85
90
|
|
86
91
|
klassify(base)
|
@@ -88,22 +93,21 @@ module Ransack
|
|
88
93
|
|
89
94
|
def association_path(str, base = @base)
|
90
95
|
base = klassify(base)
|
91
|
-
str ||=
|
96
|
+
str ||= ''.freeze
|
92
97
|
path = []
|
93
|
-
segments = str.split(
|
98
|
+
segments = str.split(Constants::UNDERSCORE)
|
94
99
|
association_parts = []
|
95
|
-
|
96
|
-
while segments.
|
97
|
-
|
98
|
-
|
100
|
+
unless segments.empty?
|
101
|
+
while !segments.empty? &&
|
102
|
+
!base.columns_hash[segments.join(Constants::UNDERSCORE)] &&
|
103
|
+
association_parts << segments.shift
|
99
104
|
assoc, klass = unpolymorphize_association(
|
100
105
|
association_parts.join(Constants::UNDERSCORE)
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
106
|
+
)
|
107
|
+
next unless found_assoc = get_association(assoc, base)
|
108
|
+
path += association_parts
|
109
|
+
association_parts = []
|
110
|
+
base = klassify(klass || found_assoc)
|
107
111
|
end
|
108
112
|
end
|
109
113
|
|
@@ -118,9 +122,13 @@ module Ransack
|
|
118
122
|
end
|
119
123
|
end
|
120
124
|
|
125
|
+
def ransackable_alias(str)
|
126
|
+
klass._ransack_aliases.fetch(str, str)
|
127
|
+
end
|
128
|
+
|
121
129
|
def ransackable_attribute?(str, klass)
|
122
130
|
klass.ransackable_attributes(auth_object).include?(str) ||
|
123
|
-
|
131
|
+
klass.ransortable_attributes(auth_object).include?(str)
|
124
132
|
end
|
125
133
|
|
126
134
|
def ransackable_association?(str, klass)
|
@@ -128,18 +136,22 @@ module Ransack
|
|
128
136
|
end
|
129
137
|
|
130
138
|
def ransackable_scope?(str, klass)
|
131
|
-
klass.ransackable_scopes(auth_object).any? { |s| s.
|
139
|
+
klass.ransackable_scopes(auth_object).any? { |s| s.to_sym == str.to_sym }
|
140
|
+
end
|
141
|
+
|
142
|
+
def ransackable_scope_skip_sanitize_args?(str, klass)
|
143
|
+
klass.ransackable_scopes_skip_sanitize_args.any? { |s| s.to_sym == str.to_sym }
|
132
144
|
end
|
133
145
|
|
134
|
-
def searchable_attributes(str =
|
146
|
+
def searchable_attributes(str = ''.freeze)
|
135
147
|
traverse(str).ransackable_attributes(auth_object)
|
136
148
|
end
|
137
149
|
|
138
|
-
def sortable_attributes(str =
|
150
|
+
def sortable_attributes(str = ''.freeze)
|
139
151
|
traverse(str).ransortable_attributes(auth_object)
|
140
152
|
end
|
141
153
|
|
142
|
-
def searchable_associations(str =
|
154
|
+
def searchable_associations(str = ''.freeze)
|
143
155
|
traverse(str).ransackable_associations(auth_object)
|
144
156
|
end
|
145
157
|
end
|