forty_facets 0.0.1 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -1
- data/forty_facets.gemspec +1 -1
- data/lib/forty_facets/facet_search.rb +93 -10
- data/lib/forty_facets/version.rb +1 -1
- metadata +2 -3
- data/demo.gif +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e439d4f05f7a8bfe44665eec3bed14cf9d323e2
|
4
|
+
data.tar.gz: c2c5a838fe3489158e5a88947e30cedfe68472b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35018e26f1a6a037cf48d9e48d5df2fcd4df016758b4a5f91314b5f1b7ae6d36c5c91e6bd85d4f372417447fca70545469be79c2f6b8ff74aa94309eecf2d273
|
7
|
+
data.tar.gz: 337b7d8da1cfb036564bb03b1e997e0fd4de8d705d3efab261ec5bd5cc657f21f62a8c0a6f3b0c54b86f377644c35b0e8435ef0dfd7c4ed31555911965306989
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@ FortyFacets lets you easily build explorative search interfaces based on fields
|
|
4
4
|
|
5
5
|
![demo](demo.gif)
|
6
6
|
|
7
|
+
Try a [working demo](http://forty-facets-demo.herokuapp.com/ "Testinstallation on heroku")!
|
8
|
+
|
7
9
|
It offers a simple API to create an interactive UI to browse your data by iteratively adding
|
8
10
|
filter values.
|
9
11
|
|
@@ -88,9 +90,15 @@ Use the search object to display further narrowing options to the user
|
|
88
90
|
%span.count= "(#{facet_value.count})"
|
89
91
|
```
|
90
92
|
|
93
|
+
## FAQ
|
94
|
+
|
95
|
+
### Can I create filter for `has_many` associations ?
|
96
|
+
|
97
|
+
No. At the moment only objects directly related via a `belongs_to` can be used as filter.
|
98
|
+
|
91
99
|
## Contributing
|
92
100
|
|
93
|
-
1. Fork it ( http://github.com
|
101
|
+
1. Fork it ( http://github.com/fortytools/forty_facets/fork )
|
94
102
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
95
103
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
96
104
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/forty_facets.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = "https://github.com/fortytools/forty_facets"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
|
-
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject{|f| f == 'demo.gif'}
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module FortyFacets
|
2
2
|
class FacetSearch
|
3
|
-
attr_reader :filters
|
3
|
+
attr_reader :filters, :orders
|
4
|
+
|
4
5
|
|
5
6
|
FieldDefinition = Struct.new(:search, :model_field, :options) do
|
6
7
|
def request_param
|
@@ -27,6 +28,42 @@ module FortyFacets
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
31
|
+
class RangeField < FieldDefinition
|
32
|
+
class RangeFilter < Filter
|
33
|
+
def build_scope
|
34
|
+
return Proc.new { |base| base } if empty?
|
35
|
+
Proc.new { |base| base.where("#{field_definition.model_field} >= ? AND #{field_definition.model_field} <= ? ", min_value, max_value ) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def min_value
|
39
|
+
return nil if empty?
|
40
|
+
value.split(' - ').first
|
41
|
+
end
|
42
|
+
|
43
|
+
def max_value
|
44
|
+
return nil if empty?
|
45
|
+
value.split(' - ').last
|
46
|
+
end
|
47
|
+
|
48
|
+
def absolute_interval
|
49
|
+
@abosultes ||= without.result.select("min(#{field_definition.model_field}) as min, max(#{field_definition.model_field}) as max").first
|
50
|
+
end
|
51
|
+
|
52
|
+
def absolute_min
|
53
|
+
absolute_interval.min
|
54
|
+
end
|
55
|
+
|
56
|
+
def absolute_max
|
57
|
+
absolute_interval.max
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
def build_filter(search_instance, value)
|
63
|
+
RangeFilter.new(self, search_instance, value)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
30
67
|
class TextField < FieldDefinition
|
31
68
|
class TextFilter < Filter
|
32
69
|
def build_scope
|
@@ -42,10 +79,6 @@ module FortyFacets
|
|
42
79
|
"%#{term}%"
|
43
80
|
end
|
44
81
|
end
|
45
|
-
|
46
|
-
def display_value
|
47
|
-
value
|
48
|
-
end
|
49
82
|
end
|
50
83
|
|
51
84
|
def build_filter(search_instance, value)
|
@@ -137,10 +170,40 @@ module FortyFacets
|
|
137
170
|
definitions << TextField.new(self, model_field, opts)
|
138
171
|
end
|
139
172
|
|
173
|
+
def range(model_field, opts = {})
|
174
|
+
definitions << RangeField.new(self, model_field, opts)
|
175
|
+
end
|
176
|
+
|
140
177
|
def facet(model_field, opts = {})
|
141
178
|
definitions << FacetField.new(self, model_field, opts)
|
142
179
|
end
|
143
180
|
|
181
|
+
OrderDefinition = Struct.new(:title, :clause) do
|
182
|
+
def build(search, order_param)
|
183
|
+
Order.new(search, self, order_param == title.to_s)
|
184
|
+
end
|
185
|
+
|
186
|
+
def request_value
|
187
|
+
title
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
Order = Struct.new(:search, :definition, :active) do
|
192
|
+
def title
|
193
|
+
definition.title
|
194
|
+
end
|
195
|
+
|
196
|
+
def by
|
197
|
+
new_params = search.params || {}
|
198
|
+
new_params[:order] = definition.request_value
|
199
|
+
search.class.new_unwrapped(new_params)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def orders(name_and_order_options)
|
204
|
+
@order_definitions = name_and_order_options.to_a.inject([]) {|ods, no| ods << OrderDefinition.new(no.first, no.last)}
|
205
|
+
end
|
206
|
+
|
144
207
|
def definitions
|
145
208
|
@definitions ||= []
|
146
209
|
end
|
@@ -161,6 +224,10 @@ module FortyFacets
|
|
161
224
|
def request_param_name
|
162
225
|
@request_param_name ||= 'search'
|
163
226
|
end
|
227
|
+
|
228
|
+
def order_definitions
|
229
|
+
@order_definitions
|
230
|
+
end
|
164
231
|
end
|
165
232
|
|
166
233
|
def initialize(request_params)
|
@@ -169,9 +236,14 @@ module FortyFacets
|
|
169
236
|
else
|
170
237
|
{}
|
171
238
|
end
|
172
|
-
@filters = self.class.definitions.inject([]) do |
|
173
|
-
|
239
|
+
@filters = self.class.definitions.inject([]) do |filters, definition|
|
240
|
+
filters << definition.build_filter(self, params[definition.request_param])
|
174
241
|
end
|
242
|
+
|
243
|
+
@orders = self.class.order_definitions.inject([]) do |orders, definition|
|
244
|
+
orders << definition.build(self, params[:order])
|
245
|
+
end
|
246
|
+
|
175
247
|
end
|
176
248
|
|
177
249
|
def self.new_unwrapped(params)
|
@@ -179,13 +251,21 @@ module FortyFacets
|
|
179
251
|
end
|
180
252
|
|
181
253
|
def filter(filter_name)
|
182
|
-
@filters.find { |f| f.field_definition.model_field == filter_name }
|
254
|
+
filter = @filters.find { |f| f.field_definition.model_field == filter_name }
|
255
|
+
raise "unknown filter #{filter_name}" unless filter
|
256
|
+
filter
|
257
|
+
end
|
258
|
+
|
259
|
+
def order
|
260
|
+
@orders.find(&:active)
|
183
261
|
end
|
184
262
|
|
185
263
|
def result
|
186
|
-
@filters.inject(self.class.root_scope) do |previous, filter|
|
264
|
+
query = @filters.inject(self.class.root_scope) do |previous, filter|
|
187
265
|
filter.build_scope.call(previous)
|
188
266
|
end
|
267
|
+
query = query.order(order.definition.clause) if order
|
268
|
+
query
|
189
269
|
end
|
190
270
|
|
191
271
|
def wrapped_params
|
@@ -193,10 +273,12 @@ module FortyFacets
|
|
193
273
|
end
|
194
274
|
|
195
275
|
def params
|
196
|
-
@filters.inject({}) do |sum, filter|
|
276
|
+
params = @filters.inject({}) do |sum, filter|
|
197
277
|
sum[filter.field_definition.request_param] = filter.value.dup unless filter.empty?
|
198
278
|
sum
|
199
279
|
end
|
280
|
+
params[:order] = order.definition.request_value if order
|
281
|
+
params
|
200
282
|
end
|
201
283
|
|
202
284
|
def path
|
@@ -208,3 +290,4 @@ module FortyFacets
|
|
208
290
|
end
|
209
291
|
end
|
210
292
|
end
|
293
|
+
|
data/lib/forty_facets/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forty_facets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Axel Tetzlaff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -51,7 +51,6 @@ files:
|
|
51
51
|
- LICENSE.txt
|
52
52
|
- README.md
|
53
53
|
- Rakefile
|
54
|
-
- demo.gif
|
55
54
|
- forty_facets.gemspec
|
56
55
|
- lib/forty_facets.rb
|
57
56
|
- lib/forty_facets/facet_search.rb
|
data/demo.gif
DELETED
Binary file
|