ransack 1.6.6 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.travis.yml +35 -53
  4. data/CHANGELOG.md +530 -9
  5. data/CONTRIBUTING.md +63 -26
  6. data/Gemfile +24 -24
  7. data/README.md +371 -96
  8. data/Rakefile +6 -29
  9. data/lib/polyamorous/activerecord_5.2_ruby_2/join_association.rb +24 -0
  10. data/lib/polyamorous/activerecord_5.2_ruby_2/join_dependency.rb +79 -0
  11. data/lib/polyamorous/activerecord_5.2_ruby_2/reflection.rb +11 -0
  12. data/lib/polyamorous/activerecord_6.0_ruby_2/join_association.rb +1 -0
  13. data/lib/polyamorous/activerecord_6.0_ruby_2/join_dependency.rb +80 -0
  14. data/lib/polyamorous/activerecord_6.0_ruby_2/reflection.rb +1 -0
  15. data/lib/polyamorous/activerecord_6.1_ruby_2/join_association.rb +74 -0
  16. data/lib/polyamorous/activerecord_6.1_ruby_2/join_dependency.rb +93 -0
  17. data/lib/polyamorous/activerecord_6.1_ruby_2/reflection.rb +1 -0
  18. data/lib/polyamorous/join.rb +70 -0
  19. data/lib/polyamorous/polyamorous.rb +24 -0
  20. data/lib/polyamorous/swapping_reflection_class.rb +11 -0
  21. data/lib/polyamorous/tree_node.rb +7 -0
  22. data/lib/ransack/adapters/active_record/base.rb +23 -2
  23. data/lib/ransack/adapters/active_record/context.rb +206 -139
  24. data/lib/ransack/adapters/active_record/ransack/constants.rb +70 -55
  25. data/lib/ransack/adapters/active_record/ransack/context.rb +10 -18
  26. data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +43 -36
  27. data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -5
  28. data/lib/ransack/adapters/active_record/ransack/visitor.rb +23 -0
  29. data/lib/ransack/adapters/active_record.rb +11 -10
  30. data/lib/ransack/adapters.rb +64 -0
  31. data/lib/ransack/configuration.rb +91 -4
  32. data/lib/ransack/constants.rb +13 -26
  33. data/lib/ransack/context.rb +45 -40
  34. data/lib/ransack/helpers/form_builder.rb +21 -12
  35. data/lib/ransack/helpers/form_helper.rb +99 -69
  36. data/lib/ransack/locale/ar.yml +70 -0
  37. data/lib/ransack/locale/az.yml +70 -0
  38. data/lib/ransack/locale/bg.yml +70 -0
  39. data/lib/ransack/locale/ca.yml +70 -0
  40. data/lib/ransack/locale/da.yml +70 -0
  41. data/lib/ransack/locale/de.yml +70 -0
  42. data/lib/ransack/locale/el.yml +70 -0
  43. data/lib/ransack/locale/es.yml +22 -22
  44. data/lib/ransack/locale/fa.yml +70 -0
  45. data/lib/ransack/locale/fi.yml +71 -0
  46. data/lib/ransack/locale/id.yml +70 -0
  47. data/lib/ransack/locale/it.yml +70 -0
  48. data/lib/ransack/locale/ja.yml +70 -0
  49. data/lib/ransack/locale/nl.yml +4 -4
  50. data/lib/ransack/locale/pt-BR.yml +70 -0
  51. data/lib/ransack/locale/ru.yml +70 -0
  52. data/lib/ransack/locale/sk.yml +70 -0
  53. data/lib/ransack/locale/tr.yml +70 -0
  54. data/lib/ransack/locale/{zh.yml → zh-CN.yml} +13 -13
  55. data/lib/ransack/locale/zh-TW.yml +70 -0
  56. data/lib/ransack/nodes/attribute.rb +6 -3
  57. data/lib/ransack/nodes/bindable.rb +18 -6
  58. data/lib/ransack/nodes/condition.rb +85 -24
  59. data/lib/ransack/nodes/grouping.rb +17 -11
  60. data/lib/ransack/nodes/sort.rb +9 -5
  61. data/lib/ransack/nodes/value.rb +74 -68
  62. data/lib/ransack/nodes.rb +2 -3
  63. data/lib/ransack/predicate.rb +17 -20
  64. data/lib/ransack/search.rb +15 -15
  65. data/lib/ransack/translate.rb +115 -115
  66. data/lib/ransack/version.rb +1 -1
  67. data/lib/ransack/visitor.rb +1 -12
  68. data/lib/ransack.rb +11 -17
  69. data/logo/ransack-h.png +0 -0
  70. data/logo/ransack-h.svg +34 -0
  71. data/logo/ransack-v.png +0 -0
  72. data/logo/ransack-v.svg +34 -0
  73. data/logo/ransack.png +0 -0
  74. data/logo/ransack.svg +21 -0
  75. data/ransack.gemspec +9 -27
  76. data/spec/console.rb +4 -0
  77. data/spec/helpers/polyamorous_helper.rb +19 -0
  78. data/spec/polyamorous/join_association_spec.rb +35 -0
  79. data/spec/polyamorous/join_dependency_spec.rb +97 -0
  80. data/spec/polyamorous/join_spec.rb +19 -0
  81. data/spec/ransack/adapters/active_record/base_spec.rb +380 -91
  82. data/spec/ransack/adapters/active_record/context_spec.rb +72 -33
  83. data/spec/ransack/configuration_spec.rb +87 -14
  84. data/spec/ransack/helpers/form_builder_spec.rb +2 -11
  85. data/spec/ransack/helpers/form_helper_spec.rb +481 -113
  86. data/spec/ransack/nodes/condition_spec.rb +25 -1
  87. data/spec/ransack/nodes/grouping_spec.rb +62 -6
  88. data/spec/ransack/predicate_spec.rb +79 -5
  89. data/spec/ransack/search_spec.rb +159 -79
  90. data/spec/spec_helper.rb +8 -0
  91. data/spec/support/schema.rb +99 -37
  92. metadata +57 -184
  93. data/lib/ransack/adapters/active_record/3.0/compat.rb +0 -179
  94. data/lib/ransack/adapters/active_record/3.0/context.rb +0 -205
  95. data/lib/ransack/adapters/active_record/3.1/context.rb +0 -219
  96. data/lib/ransack/adapters/active_record/3.2/context.rb +0 -44
  97. data/lib/ransack/adapters/active_record/compat.rb +0 -14
  98. data/lib/ransack/adapters/mongoid/3.2/.gitkeep +0 -0
  99. data/lib/ransack/adapters/mongoid/attributes/attribute.rb +0 -37
  100. data/lib/ransack/adapters/mongoid/attributes/order_predications.rb +0 -17
  101. data/lib/ransack/adapters/mongoid/attributes/predications.rb +0 -141
  102. data/lib/ransack/adapters/mongoid/base.rb +0 -126
  103. data/lib/ransack/adapters/mongoid/context.rb +0 -208
  104. data/lib/ransack/adapters/mongoid/inquiry_hash.rb +0 -23
  105. data/lib/ransack/adapters/mongoid/ransack/constants.rb +0 -88
  106. data/lib/ransack/adapters/mongoid/ransack/context.rb +0 -60
  107. data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +0 -27
  108. data/lib/ransack/adapters/mongoid/ransack/translate.rb +0 -13
  109. data/lib/ransack/adapters/mongoid/ransack/visitor.rb +0 -24
  110. data/lib/ransack/adapters/mongoid/table.rb +0 -35
  111. data/lib/ransack/adapters/mongoid.rb +0 -13
  112. data/spec/mongoid/adapters/mongoid/base_spec.rb +0 -276
  113. data/spec/mongoid/adapters/mongoid/context_spec.rb +0 -56
  114. data/spec/mongoid/configuration_spec.rb +0 -102
  115. data/spec/mongoid/dependencies_spec.rb +0 -8
  116. data/spec/mongoid/helpers/ransack_helper.rb +0 -11
  117. data/spec/mongoid/nodes/condition_spec.rb +0 -34
  118. data/spec/mongoid/nodes/grouping_spec.rb +0 -13
  119. data/spec/mongoid/predicate_spec.rb +0 -155
  120. data/spec/mongoid/search_spec.rb +0 -446
  121. data/spec/mongoid/support/mongoid.yml +0 -6
  122. data/spec/mongoid/support/schema.rb +0 -128
  123. data/spec/mongoid/translate_spec.rb +0 -14
  124. data/spec/mongoid_spec_helper.rb +0 -59
  125. data/spec/ransack/dependencies_spec.rb +0 -10
@@ -3,56 +3,63 @@ module Ransack
3
3
  class Condition
4
4
 
5
5
  def arel_predicate
6
- arel_predicate_for(attributes_array)
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 attributes_array
12
- attributes.map do |a|
13
- a.attr.send(
14
- arel_predicate_for_attribute(a), formatted_values_for_attribute(a)
15
- )
16
- end
26
+ def combinator_method
27
+ combinator === Constants::OR ? :or : :and
17
28
  end
18
29
 
19
- def arel_predicate_for(predicates)
20
- if predicates.size > 1
21
- combinator_for(predicates)
22
- else
23
- format_predicate(predicates.first)
24
- end
25
- 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)
26
34
 
27
- def combinator_for(predicates)
28
- if combinator === Constants::AND
29
- Arel::Nodes::Grouping.new(Arel::Nodes::And.new(predicates))
30
- elsif combinator === Constants::OR
31
- predicates.inject(&:or)
32
- end
33
- end
34
-
35
- def format_predicate(predicate)
36
- predicate.tap do
37
- if casted_array_with_in_predicate?(predicate)
38
- predicate.right[0] = predicate.right[0].val.map { |v| format(v) }
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 casted_array_with_in_predicate?(predicate)
44
+ def in_predicate?(predicate)
44
45
  return unless defined?(Arel::Nodes::Casted)
45
- predicate.class == Arel::Nodes::In &&
46
- predicate.right[0].respond_to?(:val) &&
47
- predicate.right[0].val.is_a?(Array)
46
+ predicate.class == Arel::Nodes::In || predicate.class == Arel::Nodes::NotIn
48
47
  end
49
48
 
50
- # Necessary for Arel >= 6.0 (Rails >= 4.2)
51
- def format(value)
52
- if value.is_a?(String)
53
- Arel::Nodes.build_quoted(value)
54
- else
55
- value
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
52
+ end
53
+
54
+ def format_values_for(predicate)
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
56
63
  end
57
64
  end
58
65
 
@@ -2,11 +2,7 @@ module Ransack
2
2
  module Translate
3
3
 
4
4
  def self.i18n_key(klass)
5
- if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
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
- case ActiveRecord::VERSION::STRING
5
- when /^3\.0\./
6
- require 'ransack/adapters/active_record/3.0/context'
7
- when /^3\.1\./
8
- require 'ransack/adapters/active_record/3.1/context'
9
- when /^3\.2\./
10
- require 'ransack/adapters/active_record/3.2/context'
11
- else
12
- require 'ransack/adapters/active_record/context'
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'
@@ -0,0 +1,64 @@
1
+ module Ransack
2
+ module Adapters
3
+
4
+ def self.object_mapper
5
+ @object_mapper ||= instantiate_object_mapper
6
+ end
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
16
+ end
17
+
18
+ class ActiveRecordAdapter
19
+ def require_constants
20
+ require 'ransack/adapters/active_record/ransack/constants'
21
+ end
22
+
23
+ def require_adapter
24
+ require 'ransack/adapters/active_record/ransack/translate'
25
+ require 'ransack/adapters/active_record'
26
+ end
27
+
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
47
+ require 'ransack/adapters/mongoid/ransack/translate'
48
+ require 'ransack/adapters/mongoid'
49
+ end
50
+
51
+ def require_context
52
+ require 'ransack/adapters/mongoid/ransack/visitor'
53
+ end
54
+
55
+ def require_nodes
56
+ require 'ransack/adapters/mongoid/ransack/nodes/condition'
57
+ end
58
+
59
+ def require_search
60
+ require 'ransack/adapters/mongoid/ransack/context'
61
+ end
62
+ end
63
+ end
64
+ end
@@ -5,10 +5,35 @@ module Ransack
5
5
  module Configuration
6
6
 
7
7
  mattr_accessor :predicates, :options
8
- self.predicates = {}
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 => '&#9660;'.freeze,
34
+ :down_arrow => '&#9650;'.freeze,
35
+ :default_arrow => nil,
36
+ :sanitize_scope_args => true
12
37
  }
13
38
 
14
39
  def configure
@@ -61,12 +86,74 @@ module Ransack
61
86
  self.options[:search_key] = name
62
87
  end
63
88
 
64
- # Raise an error if an unknown predicate, condition or attribute is passed
65
- # into a search.
89
+ # By default Ransack ignores errors if an unknown predicate, condition or
90
+ # attribute is passed into a search. The default may be overridden in an
91
+ # initializer file like `config/initializers/ransack.rb` as follows:
92
+ #
93
+ # Ransack.configure do |config|
94
+ # # Raise if an unknown predicate, condition or attribute is passed
95
+ # config.ignore_unknown_conditions = false
96
+ # end
97
+ #
66
98
  def ignore_unknown_conditions=(boolean)
67
99
  self.options[:ignore_unknown_conditions] = boolean
68
100
  end
69
101
 
102
+ # By default, Ransack displays sort order indicator arrows with HTML codes:
103
+ #
104
+ # up_arrow: '&#9660;'
105
+ # down_arrow: '&#9650;'
106
+ #
107
+ # There is also a default arrow which is displayed if a column is not sorted.
108
+ # By default this is nil so nothing will be displayed.
109
+ #
110
+ # Any of the defaults may be globally overridden in an initializer file
111
+ # like `config/initializers/ransack.rb` as follows:
112
+ #
113
+ # Ransack.configure do |config|
114
+ # # Globally set the up arrow to an icon, and the down and default arrows to unicode.
115
+ # config.custom_arrows = {
116
+ # up_arrow: '<i class="fa fa-long-arrow-up"></i>',
117
+ # down_arrow: 'U+02193',
118
+ # default_arrow: 'U+11047'
119
+ # }
120
+ # end
121
+ #
122
+ def custom_arrows=(opts = {})
123
+ self.options[:up_arrow] = opts[:up_arrow].freeze if opts[:up_arrow]
124
+ self.options[:down_arrow] = opts[:down_arrow].freeze if opts[:down_arrow]
125
+ self.options[:default_arrow] = opts[:default_arrow].freeze if opts[:default_arrow]
126
+ end
127
+
128
+ # Ransack sanitizes many values in your custom scopes into booleans.
129
+ # [1, '1', 't', 'T', 'true', 'TRUE'] all evaluate to true.
130
+ # [0, '0', 'f', 'F', 'false', 'FALSE'] all evaluate to false.
131
+ #
132
+ # This default may be globally overridden in an initializer file like
133
+ # `config/initializers/ransack.rb` as follows:
134
+ #
135
+ # Ransack.configure do |config|
136
+ # # Accept my custom scope values as what they are.
137
+ # config.sanitize_custom_scope_booleans = false
138
+ # end
139
+ #
140
+ def sanitize_custom_scope_booleans=(boolean)
141
+ self.options[:sanitize_scope_args] = boolean
142
+ end
143
+
144
+ # By default, Ransack displays sort order indicator arrows in sort links.
145
+ # The default may be globally overridden in an initializer file like
146
+ # `config/initializers/ransack.rb` as follows:
147
+ #
148
+ # Ransack.configure do |config|
149
+ # # Hide sort link order indicators globally across the application
150
+ # config.hide_sort_order_indicators = true
151
+ # end
152
+ #
153
+ def hide_sort_order_indicators=(boolean)
154
+ self.options[:hide_sort_order_indicators] = boolean
155
+ end
156
+
70
157
  def arel_predicate_with_suffix(arel_predicate, suffix)
71
158
  if arel_predicate === Proc
72
159
  proc { |v| "#{arel_predicate.call(v)}#{suffix}" }
@@ -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 = '&#9650;'.freeze
8
- DESC_ARROW = '&#9660;'.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 = '&nbsp;'.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
- S_SORTS = %w(s sorts).freeze
48
- AND_OR = %w(and or).freeze
49
- IN_NOT_IN = %w(in not_in).freeze
50
- SUFFIXES = %w(_any _all).freeze
51
- AREL_PREDICATES = %w(
52
- eq not_eq matches does_not_match lt lteq gt gteq in not_in
53
- ).freeze
54
- A_S_I = %w(a s i).freeze
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
- RAILS_4_1 = '4.1'.freeze
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
@@ -1,12 +1,5 @@
1
1
  require 'ransack/visitor'
2
-
3
- if defined?(::ActiveRecord::Base)
4
- require 'ransack/adapters/active_record/ransack/visitor'
5
- end
6
-
7
- if defined?(::Mongoid)
8
- require 'ransack/adapters/mongoid/ransack/visitor'
9
- end
2
+ Ransack::Adapters.object_mapper.require_context
10
3
 
11
4
  module Ransack
12
5
  class Context
@@ -24,9 +17,12 @@ module Ransack
24
17
  end
25
18
 
26
19
  def for(object, options = {})
27
- context = Class === object ?
28
- for_class(object, options) :
29
- for_object(object, options)
20
+ context =
21
+ if Class === object
22
+ for_class(object, options)
23
+ else
24
+ for_object(object, options)
25
+ end
30
26
  context or raise ArgumentError,
31
27
  "Don't know what context to use for #{object}"
32
28
  end
@@ -44,7 +40,7 @@ module Ransack
44
40
  # Convert a string representing a chain of associations and an attribute
45
41
  # into the attribute itself
46
42
  def contextualize(str)
47
- parent, attr_name = @bind_pairs[str]
43
+ parent, attr_name = bind_pair_for(str)
48
44
  table_for(parent)[attr_name]
49
45
  end
50
46
 
@@ -62,32 +58,34 @@ module Ransack
62
58
  end
63
59
 
64
60
  def bind(object, str)
65
- object.parent, object.attr_name = @bind_pairs[str]
61
+ return nil unless str
62
+ object.parent, object.attr_name = bind_pair_for(str)
66
63
  end
67
64
 
68
65
  def traverse(str, base = @base)
69
- str ||= Constants::EMPTY
70
-
71
- if (segments = str.split(/_/)).size > 0
66
+ str ||= ''.freeze
67
+ segments = str.split(Constants::UNDERSCORE)
68
+ unless segments.empty?
72
69
  remainder = []
73
70
  found_assoc = nil
74
- while !found_assoc && segments.size > 0 do
71
+ until found_assoc || segments.empty?
75
72
  # Strip the _of_Model_type text from the association name, but hold
76
73
  # onto it in klass, for use as the next base
77
74
  assoc, klass = unpolymorphize_association(
78
75
  segments.join(Constants::UNDERSCORE)
79
- )
76
+ )
80
77
  if found_assoc = get_association(assoc, base)
81
78
  base = traverse(
82
- remainder.join(
83
- Constants::UNDERSCORE), klass || found_assoc.klass
84
- )
79
+ remainder.join(Constants::UNDERSCORE), klass || found_assoc.klass
80
+ )
85
81
  end
86
82
 
87
83
  remainder.unshift segments.pop
88
84
  end
89
- raise UntraversableAssociationError,
90
- "No association matches #{str}" unless found_assoc
85
+ unless found_assoc
86
+ raise(UntraversableAssociationError,
87
+ "No association matches #{str}")
88
+ end
91
89
  end
92
90
 
93
91
  klassify(base)
@@ -95,22 +93,21 @@ module Ransack
95
93
 
96
94
  def association_path(str, base = @base)
97
95
  base = klassify(base)
98
- str ||= Constants::EMPTY
96
+ str ||= ''.freeze
99
97
  path = []
100
- segments = str.split(/_/)
98
+ segments = str.split(Constants::UNDERSCORE)
101
99
  association_parts = []
102
- if (segments = str.split(/_/)).size > 0
103
- while segments.size > 0 &&
104
- !base.columns_hash[segments.join(Constants::UNDERSCORE)] &&
105
- association_parts << segments.shift do
100
+ unless segments.empty?
101
+ while !segments.empty? &&
102
+ !base.columns_hash[segments.join(Constants::UNDERSCORE)] &&
103
+ association_parts << segments.shift
106
104
  assoc, klass = unpolymorphize_association(
107
105
  association_parts.join(Constants::UNDERSCORE)
108
- )
109
- if found_assoc = get_association(assoc, base)
110
- path += association_parts
111
- association_parts = []
112
- base = klassify(klass || found_assoc)
113
- end
106
+ )
107
+ next unless found_assoc = get_association(assoc, base)
108
+ path += association_parts
109
+ association_parts = []
110
+ base = klassify(klass || found_assoc)
114
111
  end
115
112
  end
116
113
 
@@ -125,9 +122,13 @@ module Ransack
125
122
  end
126
123
  end
127
124
 
125
+ def ransackable_alias(str)
126
+ klass._ransack_aliases.fetch(str, str)
127
+ end
128
+
128
129
  def ransackable_attribute?(str, klass)
129
130
  klass.ransackable_attributes(auth_object).include?(str) ||
130
- klass.ransortable_attributes(auth_object).include?(str)
131
+ klass.ransortable_attributes(auth_object).include?(str)
131
132
  end
132
133
 
133
134
  def ransackable_association?(str, klass)
@@ -135,18 +136,22 @@ module Ransack
135
136
  end
136
137
 
137
138
  def ransackable_scope?(str, klass)
138
- klass.ransackable_scopes(auth_object).any? { |s| s.to_s == str }
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 }
139
144
  end
140
145
 
141
- def searchable_attributes(str = Constants::EMPTY)
146
+ def searchable_attributes(str = ''.freeze)
142
147
  traverse(str).ransackable_attributes(auth_object)
143
148
  end
144
149
 
145
- def sortable_attributes(str = Constants::EMPTY)
150
+ def sortable_attributes(str = ''.freeze)
146
151
  traverse(str).ransortable_attributes(auth_object)
147
152
  end
148
153
 
149
- def searchable_associations(str = Constants::EMPTY)
154
+ def searchable_associations(str = ''.freeze)
150
155
  traverse(str).ransackable_associations(auth_object)
151
156
  end
152
157
  end
@@ -6,8 +6,14 @@ module ActionView::Helpers::Tags
6
6
  # https://github.com/rails/rails/commit/c1a118a
7
7
  class Base
8
8
  private
9
- def value(object)
10
- object.send @method_name if object # use send instead of public_send
9
+ if defined? ::ActiveRecord
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
15
+ end
16
+ end
11
17
  end
12
18
  end
13
19
  end
@@ -15,8 +21,7 @@ end
15
21
  RANSACK_FORM_BUILDER = 'RANSACK_FORM_BUILDER'.freeze
16
22
 
17
23
  require 'simple_form' if
18
- (ENV[RANSACK_FORM_BUILDER] || Ransack::Constants::EMPTY)
19
- .match('SimpleForm'.freeze)
24
+ (ENV[RANSACK_FORM_BUILDER] || ''.freeze).match('SimpleForm'.freeze)
20
25
 
21
26
  module Ransack
22
27
  module Helpers
@@ -47,7 +52,7 @@ module Ransack
47
52
  raise ArgumentError, formbuilder_error_message(
48
53
  "#{action}_select") unless object.respond_to?(:context)
49
54
  options[:include_blank] = true unless options.has_key?(:include_blank)
50
- bases = [Constants::EMPTY] + association_array(options[:associations])
55
+ bases = [''.freeze].freeze + association_array(options[:associations])
51
56
  if bases.size > 1
52
57
  collection = attribute_collection_for_bases(action, bases)
53
58
  object.name ||= default if can_use_default?(
@@ -66,13 +71,13 @@ module Ransack
66
71
  def sort_direction_select(options = {}, html_options = {})
67
72
  unless object.respond_to?(:context)
68
73
  raise ArgumentError,
69
- formbuilder_error_message(Constants::SORT_DIRECTION)
74
+ formbuilder_error_message('sort_direction'.freeze)
70
75
  end
71
76
  template_collection_select(:dir, sort_array, options, html_options)
72
77
  end
73
78
 
74
79
  def sort_select(options = {}, html_options = {})
75
- attribute_select(options, html_options, Constants::SORT) +
80
+ attribute_select(options, html_options, 'sort'.freeze) +
76
81
  sort_direction_select(options, html_options)
77
82
  end
78
83
 
@@ -84,6 +89,10 @@ module Ransack
84
89
  @template.sort_link @object, attribute, *args
85
90
  end
86
91
 
92
+ def sort_url(attribute, *args)
93
+ @template.sort_url @object, attribute, *args
94
+ end
95
+
87
96
  def condition_fields(*args, &block)
88
97
  search_fields(:c, args, block)
89
98
  end
@@ -135,7 +144,7 @@ module Ransack
135
144
  else
136
145
  only = Array.wrap(only).map(&:to_s)
137
146
  keys = keys.select {
138
- |k| only.include? k.sub(/_(any|all)$/, Constants::EMPTY)
147
+ |k| only.include? k.sub(/_(any|all)$/, ''.freeze)
139
148
  }
140
149
  end
141
150
  end
@@ -177,9 +186,9 @@ module Ransack
177
186
 
178
187
  def sort_array
179
188
  [
180
- [Constants::ASC, object.translate(Constants::ASC)],
181
- [Constants::DESC, object.translate(Constants::DESC)]
182
- ]
189
+ ['asc'.freeze, object.translate('asc'.freeze)].freeze,
190
+ ['desc'.freeze, object.translate('desc'.freeze)].freeze
191
+ ].freeze
183
192
  end
184
193
 
185
194
  def combinator_choices
@@ -234,7 +243,7 @@ module Ransack
234
243
  Translate.association(base, :context => object.context),
235
244
  collection_for_base(action, base)
236
245
  ]
237
- rescue UntraversableAssociationError => e
246
+ rescue UntraversableAssociationError
238
247
  nil
239
248
  end
240
249
  end