ransack 1.5.1 → 1.6.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/.travis.yml +47 -3
- data/CHANGELOG.md +106 -18
- data/CONTRIBUTING.md +56 -23
- data/Gemfile +16 -5
- data/README.md +114 -38
- data/Rakefile +30 -2
- data/lib/ransack.rb +9 -0
- data/lib/ransack/adapters/active_record/3.0/compat.rb +11 -8
- data/lib/ransack/adapters/active_record/3.0/context.rb +14 -22
- data/lib/ransack/adapters/active_record/3.1/context.rb +14 -22
- data/lib/ransack/adapters/active_record/context.rb +36 -31
- data/lib/ransack/adapters/active_record/ransack/constants.rb +113 -0
- data/lib/ransack/adapters/active_record/ransack/context.rb +64 -0
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +48 -0
- data/lib/ransack/adapters/active_record/ransack/translate.rb +12 -0
- data/lib/ransack/adapters/active_record/ransack/visitor.rb +24 -0
- data/lib/ransack/adapters/mongoid.rb +13 -0
- data/lib/ransack/adapters/mongoid/3.2/.gitkeep +0 -0
- data/lib/ransack/adapters/mongoid/attributes/attribute.rb +37 -0
- data/lib/ransack/adapters/mongoid/attributes/order_predications.rb +17 -0
- data/lib/ransack/adapters/mongoid/attributes/predications.rb +141 -0
- data/lib/ransack/adapters/mongoid/base.rb +126 -0
- data/lib/ransack/adapters/mongoid/context.rb +208 -0
- data/lib/ransack/adapters/mongoid/inquiry_hash.rb +23 -0
- data/lib/ransack/adapters/mongoid/ransack/constants.rb +88 -0
- data/lib/ransack/adapters/mongoid/ransack/context.rb +60 -0
- data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +27 -0
- data/lib/ransack/adapters/mongoid/ransack/translate.rb +13 -0
- data/lib/ransack/adapters/mongoid/ransack/visitor.rb +24 -0
- data/lib/ransack/adapters/mongoid/table.rb +35 -0
- data/lib/ransack/configuration.rb +22 -4
- data/lib/ransack/constants.rb +26 -120
- data/lib/ransack/context.rb +32 -60
- data/lib/ransack/helpers/form_builder.rb +50 -36
- data/lib/ransack/helpers/form_helper.rb +148 -104
- data/lib/ransack/naming.rb +11 -11
- data/lib/ransack/nodes.rb +2 -0
- data/lib/ransack/nodes/bindable.rb +12 -4
- data/lib/ransack/nodes/condition.rb +5 -22
- data/lib/ransack/nodes/grouping.rb +9 -10
- data/lib/ransack/nodes/sort.rb +3 -2
- data/lib/ransack/nodes/value.rb +1 -2
- data/lib/ransack/predicate.rb +3 -3
- data/lib/ransack/search.rb +46 -13
- data/lib/ransack/translate.rb +8 -8
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +4 -16
- data/ransack.gemspec +1 -0
- data/spec/mongoid/adapters/mongoid/base_spec.rb +276 -0
- data/spec/mongoid/adapters/mongoid/context_spec.rb +56 -0
- data/spec/mongoid/configuration_spec.rb +66 -0
- data/spec/mongoid/dependencies_spec.rb +8 -0
- data/spec/mongoid/helpers/ransack_helper.rb +11 -0
- data/spec/mongoid/nodes/condition_spec.rb +34 -0
- data/spec/mongoid/nodes/grouping_spec.rb +13 -0
- data/spec/mongoid/predicate_spec.rb +155 -0
- data/spec/mongoid/search_spec.rb +446 -0
- data/spec/mongoid/support/mongoid.yml +6 -0
- data/spec/mongoid/support/schema.rb +128 -0
- data/spec/mongoid/translate_spec.rb +14 -0
- data/spec/mongoid_spec_helper.rb +59 -0
- data/spec/ransack/adapters/active_record/base_spec.rb +68 -35
- data/spec/ransack/dependencies_spec.rb +3 -1
- data/spec/ransack/helpers/form_builder_spec.rb +6 -6
- data/spec/ransack/helpers/form_helper_spec.rb +114 -47
- data/spec/ransack/nodes/condition_spec.rb +2 -2
- data/spec/ransack/search_spec.rb +2 -6
- data/spec/ransack/translate_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -3
- data/spec/support/schema.rb +9 -0
- metadata +49 -4
@@ -2,21 +2,25 @@ module Ransack
|
|
2
2
|
module Helpers
|
3
3
|
module FormHelper
|
4
4
|
|
5
|
+
# +search_form_for+
|
6
|
+
#
|
7
|
+
# <%= search_form_for(@q) do |f| %>
|
8
|
+
#
|
5
9
|
def search_form_for(record, options = {}, &proc)
|
6
|
-
if record.is_a?
|
10
|
+
if record.is_a? Ransack::Search
|
7
11
|
search = record
|
8
12
|
options[:url] ||= polymorphic_path(
|
9
13
|
search.klass, format: options.delete(:format)
|
10
14
|
)
|
11
|
-
elsif record.is_a?
|
12
|
-
(search = record.detect { |o| o.is_a?
|
15
|
+
elsif record.is_a? Array &&
|
16
|
+
(search = record.detect { |o| o.is_a? Ransack::Search })
|
13
17
|
options[:url] ||= polymorphic_path(
|
14
|
-
record.map { |o| o.is_a?
|
18
|
+
record.map { |o| o.is_a? Ransack::Search ? o.klass : o },
|
15
19
|
format: options.delete(:format)
|
16
20
|
)
|
17
21
|
else
|
18
22
|
raise ArgumentError,
|
19
|
-
|
23
|
+
'No Ransack::Search object was provided to search_form_for!'
|
20
24
|
end
|
21
25
|
options[:html] ||= {}
|
22
26
|
html_options = {
|
@@ -28,135 +32,175 @@ module Ransack
|
|
28
32
|
"#{search.klass.to_s.underscore}_search",
|
29
33
|
:method => :get
|
30
34
|
}
|
31
|
-
options[:as] ||= Ransack
|
35
|
+
options[:as] ||= Ransack.options[:search_key]
|
32
36
|
options[:html].reverse_merge!(html_options)
|
33
37
|
options[:builder] ||= FormBuilder
|
34
38
|
|
35
39
|
form_for(record, options, &proc)
|
36
40
|
end
|
37
41
|
|
38
|
-
# sort_link
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
# +sort_link+
|
43
|
+
#
|
44
|
+
# <%= sort_link(@q, :name, [:name, 'kind ASC'], 'Player Name') %>
|
45
|
+
#
|
46
|
+
def sort_link(search_object, attribute, *args)
|
47
|
+
search, routing_proxy = extract_search_and_routing_proxy(search_object)
|
48
|
+
unless Search === search
|
49
|
+
raise TypeError, 'First argument must be a Ransack::Search!'
|
44
50
|
end
|
51
|
+
s = SortLink.new(search, attribute, args, params)
|
52
|
+
link_to(s.name, url(routing_proxy, s.url_options), s.html_options(args))
|
53
|
+
end
|
45
54
|
|
46
|
-
|
47
|
-
Search === search
|
48
|
-
|
49
|
-
# This is the field that this link represents. The direction of the sort icon (up/down arrow) will
|
50
|
-
# depend on the sort status of this field
|
51
|
-
field_name = attribute.to_s
|
55
|
+
private
|
52
56
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
57
|
+
def extract_search_and_routing_proxy(search)
|
58
|
+
if search.is_a? Array
|
59
|
+
[search.second, search.first]
|
60
|
+
else
|
61
|
+
[search, nil]
|
62
|
+
end
|
58
63
|
end
|
59
64
|
|
60
|
-
|
61
|
-
if
|
62
|
-
|
65
|
+
def url(routing_proxy, options_for_url)
|
66
|
+
if routing_proxy && respond_to?(routing_proxy)
|
67
|
+
send(routing_proxy).url_for(options_for_url)
|
63
68
|
else
|
64
|
-
|
69
|
+
url_for(options_for_url)
|
65
70
|
end
|
71
|
+
end
|
66
72
|
|
67
|
-
|
68
|
-
|
69
|
-
|
73
|
+
class SortLink
|
74
|
+
def initialize(search, attribute, args, params)
|
75
|
+
@search = search
|
76
|
+
@params = params
|
77
|
+
@field = attribute.to_s
|
78
|
+
sort_fields = extract_sort_fields_and_mutate_args!(args).compact
|
79
|
+
@current_dir = existing_sort_direction
|
80
|
+
@label_text = extract_label_and_mutate_args!(args)
|
81
|
+
@options = extract_options_and_mutate_args!(args)
|
82
|
+
@hide_indicator = @options.delete :hide_indicator
|
83
|
+
@default_order = @options.delete :default_order
|
84
|
+
@sort_params = build_sort(sort_fields)
|
85
|
+
@sort_params = @sort_params.first if @sort_params.size == 1
|
86
|
+
end
|
70
87
|
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
def name
|
89
|
+
[ERB::Util.h(@label_text), order_indicator]
|
90
|
+
.compact
|
91
|
+
.join(Constants::NON_BREAKING_SPACE)
|
92
|
+
.html_safe
|
93
|
+
end
|
74
94
|
|
75
|
-
|
76
|
-
|
95
|
+
def url_options
|
96
|
+
@params.merge(
|
97
|
+
@options.merge(
|
98
|
+
@search.context.search_key => search_and_sort_params))
|
99
|
+
end
|
77
100
|
|
78
|
-
|
79
|
-
|
80
|
-
|
101
|
+
def html_options(args)
|
102
|
+
html_options = extract_options_and_mutate_args!(args)
|
103
|
+
html_options.merge(class:
|
104
|
+
[[Constants::SORT_LINK, @current_dir], html_options[:class]]
|
105
|
+
.compact.join(Constants::SPACE)
|
106
|
+
)
|
81
107
|
end
|
82
108
|
|
83
|
-
|
109
|
+
private
|
84
110
|
|
85
|
-
|
86
|
-
|
87
|
-
|
111
|
+
def extract_sort_fields_and_mutate_args!(args)
|
112
|
+
if args.first.is_a? Array
|
113
|
+
args.shift
|
114
|
+
else
|
115
|
+
[@field]
|
116
|
+
end
|
117
|
+
end
|
88
118
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
119
|
+
def extract_label_and_mutate_args!(args)
|
120
|
+
if args.first.is_a? String
|
121
|
+
args.shift
|
122
|
+
else
|
123
|
+
Translate.attribute(@field, :context => @search.context)
|
94
124
|
end
|
125
|
+
end
|
95
126
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
elsif default_order_is_a_hash
|
104
|
-
default_order[attr_name] || Ransack::Constants::ASC
|
105
|
-
else
|
106
|
-
default_order || Ransack::Constants::ASC
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
sort_params << "#{attr_name} #{new_dir}"
|
111
|
-
end
|
127
|
+
def extract_options_and_mutate_args!(args)
|
128
|
+
if args.first.is_a? Hash
|
129
|
+
args.shift.with_indifferent_access
|
130
|
+
else
|
131
|
+
{}
|
132
|
+
end
|
133
|
+
end
|
112
134
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
html_options = args.first.is_a?(Hash) ? args.shift.dup : {}
|
118
|
-
css = [Ransack::Constants::SORT_LINK, field_current_dir]
|
119
|
-
.compact.join(Ransack::Constants::SPACE)
|
120
|
-
html_options[:class] = [css, html_options[:class]]
|
121
|
-
.compact.join(Ransack::Constants::SPACE)
|
122
|
-
|
123
|
-
query_hash = {}
|
124
|
-
query_hash[search.context.search_key] = search_params
|
125
|
-
.merge(:s => sort_params)
|
126
|
-
options.merge!(query_hash)
|
127
|
-
options_for_url = params.merge(options)
|
128
|
-
|
129
|
-
url =
|
130
|
-
if routing_proxy && respond_to?(routing_proxy)
|
131
|
-
send(routing_proxy).url_for(options_for_url)
|
132
|
-
else
|
133
|
-
url_for(options_for_url)
|
134
|
-
end
|
135
|
+
def search_and_sort_params
|
136
|
+
search_params.merge(:s => @sort_params)
|
137
|
+
end
|
135
138
|
|
136
|
-
|
139
|
+
def search_params
|
140
|
+
@params[@search.context.search_key].presence || {}
|
141
|
+
end
|
137
142
|
|
138
|
-
|
139
|
-
|
143
|
+
def build_sort(fields)
|
144
|
+
return [] if fields.empty?
|
145
|
+
[parse_sort(fields[0])] + build_sort(fields.drop(1))
|
146
|
+
end
|
140
147
|
|
141
|
-
|
148
|
+
def parse_sort(field)
|
149
|
+
attr_name, new_dir = field.to_s.split(/\s+/)
|
150
|
+
if no_sort_direction_specified?(new_dir)
|
151
|
+
new_dir = detect_previous_sort_direction_and_invert_it(attr_name)
|
152
|
+
end
|
153
|
+
"#{attr_name} #{new_dir}"
|
154
|
+
end
|
142
155
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
156
|
+
def detect_previous_sort_direction_and_invert_it(attr_name)
|
157
|
+
sort_dir = existing_sort_direction(attr_name)
|
158
|
+
if sort_dir
|
159
|
+
direction_text(sort_dir)
|
160
|
+
else
|
161
|
+
default_sort_order(attr_name) || Constants::ASC
|
162
|
+
end
|
163
|
+
end
|
149
164
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
165
|
+
def existing_sort_direction(attr_name = @field)
|
166
|
+
if sort = @search.sorts.detect { |s| s && s.name == attr_name }
|
167
|
+
sort.dir
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def default_sort_order(attr_name)
|
172
|
+
Hash === @default_order ? @default_order[attr_name] : @default_order
|
173
|
+
end
|
159
174
|
|
175
|
+
def order_indicator
|
176
|
+
if @hide_indicator || no_sort_direction_specified?
|
177
|
+
nil
|
178
|
+
else
|
179
|
+
direction_arrow
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def no_sort_direction_specified?(dir = @current_dir)
|
184
|
+
!Constants::ASC_DESC.include?(dir)
|
185
|
+
end
|
186
|
+
|
187
|
+
def direction_arrow
|
188
|
+
if @current_dir == Constants::DESC
|
189
|
+
Constants::DESC_ARROW
|
190
|
+
else
|
191
|
+
Constants::ASC_ARROW
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def direction_text(dir)
|
196
|
+
if dir == Constants::DESC
|
197
|
+
Constants::ASC
|
198
|
+
else
|
199
|
+
Constants::DESC
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
160
204
|
end
|
161
205
|
end
|
162
206
|
end
|
data/lib/ransack/naming.rb
CHANGED
@@ -28,16 +28,16 @@ module Ransack
|
|
28
28
|
alias_method :cache_key, :collection
|
29
29
|
|
30
30
|
def initialize
|
31
|
-
super(
|
32
|
-
@singular
|
33
|
-
@plural
|
34
|
-
@element
|
35
|
-
@human
|
36
|
-
@collection
|
37
|
-
@partial_path =
|
38
|
-
@param_key
|
39
|
-
@route_key
|
40
|
-
@i18n_key
|
31
|
+
super(Constants::CAP_SEARCH)
|
32
|
+
@singular = Constants::SEARCH
|
33
|
+
@plural = Constants::SEARCHES
|
34
|
+
@element = Constants::SEARCH
|
35
|
+
@human = Constants::CAP_SEARCH
|
36
|
+
@collection = Constants::RANSACK_SLASH_SEARCHES
|
37
|
+
@partial_path = Constants::RANSACK_SLASH_SEARCHES_SLASH_SEARCH
|
38
|
+
@param_key = Constants::Q
|
39
|
+
@route_key = Constants::SEARCHES
|
40
|
+
@i18n_key = :ransack
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
@@ -51,4 +51,4 @@ module Ransack
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
end
|
54
|
+
end
|
data/lib/ransack/nodes.rb
CHANGED
@@ -3,5 +3,7 @@ require 'ransack/nodes/node'
|
|
3
3
|
require 'ransack/nodes/attribute'
|
4
4
|
require 'ransack/nodes/value'
|
5
5
|
require 'ransack/nodes/condition'
|
6
|
+
require 'ransack/adapters/active_record/ransack/nodes/condition' if defined?(::ActiveRecord::Base)
|
7
|
+
require 'ransack/adapters/mongoid/ransack/nodes/condition' if defined?(::Mongoid)
|
6
8
|
require 'ransack/nodes/sort'
|
7
9
|
require 'ransack/nodes/grouping'
|
@@ -5,9 +5,7 @@ module Ransack
|
|
5
5
|
attr_accessor :parent, :attr_name
|
6
6
|
|
7
7
|
def attr
|
8
|
-
@attr ||=
|
9
|
-
ransacker.attr_from(self) :
|
10
|
-
context.table_for(parent)[attr_name]
|
8
|
+
@attr ||= get_arel_attribute
|
11
9
|
end
|
12
10
|
alias :arel_attribute :attr
|
13
11
|
|
@@ -27,6 +25,16 @@ module Ransack
|
|
27
25
|
@parent = @attr_name = @attr = @klass = nil
|
28
26
|
end
|
29
27
|
|
28
|
+
private
|
29
|
+
|
30
|
+
def get_arel_attribute
|
31
|
+
if ransacker
|
32
|
+
ransacker.attr_from(self)
|
33
|
+
else
|
34
|
+
context.table_for(parent)[attr_name]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
30
38
|
end
|
31
39
|
end
|
32
|
-
end
|
40
|
+
end
|
@@ -105,7 +105,7 @@ module Ransack
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def combinator=(val)
|
108
|
-
@combinator =
|
108
|
+
@combinator = Constants::AND_OR.detect { |v| v == val.to_s } || nil
|
109
109
|
end
|
110
110
|
alias :m= :combinator=
|
111
111
|
alias :m :combinator
|
@@ -171,23 +171,7 @@ module Ransack
|
|
171
171
|
alias :p :predicate_name
|
172
172
|
|
173
173
|
def arel_predicate
|
174
|
-
|
175
|
-
attr.attr.send(
|
176
|
-
arel_predicate_for_attribute(attr),
|
177
|
-
formatted_values_for_attribute(attr)
|
178
|
-
)
|
179
|
-
end
|
180
|
-
|
181
|
-
if predicates.size > 1
|
182
|
-
case combinator
|
183
|
-
when Ransack::Constants::AND
|
184
|
-
Arel::Nodes::Grouping.new(Arel::Nodes::And.new(predicates))
|
185
|
-
when Ransack::Constants::OR
|
186
|
-
predicates.inject(&:or)
|
187
|
-
end
|
188
|
-
else
|
189
|
-
predicates.first
|
190
|
-
end
|
174
|
+
raise "not implemented"
|
191
175
|
end
|
192
176
|
|
193
177
|
def validated_values
|
@@ -228,20 +212,19 @@ module Ransack
|
|
228
212
|
data = [
|
229
213
|
['attributes'.freeze, a.try(:map, &:name)],
|
230
214
|
['predicate'.freeze, p],
|
231
|
-
[
|
215
|
+
[Constants::COMBINATOR, m],
|
232
216
|
['values'.freeze, v.try(:map, &:value)]
|
233
217
|
]
|
234
218
|
.reject { |e| e[1].blank? }
|
235
219
|
.map { |v| "#{v[0]}: #{v[1]}" }
|
236
|
-
.join(
|
220
|
+
.join(Constants::COMMA_SPACE)
|
237
221
|
"Condition <#{data}>"
|
238
222
|
end
|
239
223
|
|
240
224
|
private
|
241
225
|
|
242
226
|
def valid_combinator?
|
243
|
-
attributes.size < 2 ||
|
244
|
-
Ransack::Constants::AND_OR.include?(combinator)
|
227
|
+
attributes.size < 2 || Constants::AND_OR.include?(combinator)
|
245
228
|
end
|
246
229
|
|
247
230
|
end
|
@@ -44,7 +44,6 @@ module Ransack
|
|
44
44
|
self.conditions << condition if condition.valid?
|
45
45
|
end
|
46
46
|
end
|
47
|
-
|
48
47
|
self.conditions.uniq!
|
49
48
|
end
|
50
49
|
alias :c= :conditions=
|
@@ -69,7 +68,7 @@ module Ransack
|
|
69
68
|
def respond_to?(method_id)
|
70
69
|
super or begin
|
71
70
|
method_name = method_id.to_s
|
72
|
-
writer = method_name.sub!(/\=$/,
|
71
|
+
writer = method_name.sub!(/\=$/, Constants::EMPTY)
|
73
72
|
attribute_method?(method_name) ? true : false
|
74
73
|
end
|
75
74
|
end
|
@@ -115,11 +114,13 @@ module Ransack
|
|
115
114
|
|
116
115
|
def method_missing(method_id, *args)
|
117
116
|
method_name = method_id.to_s
|
118
|
-
writer = method_name.sub!(/\=$/,
|
117
|
+
writer = method_name.sub!(/\=$/, Constants::EMPTY)
|
119
118
|
if attribute_method?(method_name)
|
120
|
-
writer
|
121
|
-
write_attribute(method_name, *args)
|
119
|
+
if writer
|
120
|
+
write_attribute(method_name, *args)
|
121
|
+
else
|
122
122
|
read_attribute(method_name)
|
123
|
+
end
|
123
124
|
else
|
124
125
|
super
|
125
126
|
end
|
@@ -135,8 +136,7 @@ module Ransack
|
|
135
136
|
else
|
136
137
|
stripped_name
|
137
138
|
.split(/_and_|_or_/)
|
138
|
-
.
|
139
|
-
.empty?
|
139
|
+
.none? { |n| !@context.attribute_method?(n) }
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
@@ -165,12 +165,11 @@ module Ransack
|
|
165
165
|
|
166
166
|
def inspect
|
167
167
|
data = [
|
168
|
-
['conditions'.freeze, conditions],
|
169
|
-
[Ransack::Constants::COMBINATOR, combinator]
|
168
|
+
['conditions'.freeze, conditions], [Constants::COMBINATOR, combinator]
|
170
169
|
]
|
171
170
|
.reject { |e| e[1].blank? }
|
172
171
|
.map { |v| "#{v[0]}: #{v[1]}" }
|
173
|
-
.join(
|
172
|
+
.join(Constants::COMMA_SPACE)
|
174
173
|
"Grouping <#{data}>"
|
175
174
|
end
|
176
175
|
|