ransack 1.7.0 → 2.4.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 +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
|