repertoire-faceting 0.5.2 → 0.5.3
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.
- data/FAQ +88 -91
- data/INSTALL +186 -174
- data/README +158 -370
- data/TODO +21 -32
- data/lib/repertoire-faceting/adapters/postgresql_adapter.rb +3 -12
- data/lib/repertoire-faceting/controller.rb +36 -3
- data/lib/repertoire-faceting/model.rb +45 -22
- data/lib/repertoire-faceting/routing.rb +9 -7
- data/lib/repertoire-faceting/version.rb +1 -1
- metadata +3 -3
data/FAQ
CHANGED
@@ -1,42 +1,54 @@
|
|
1
|
-
= Repertoire Faceting FAQ
|
1
|
+
= Repertoire Faceting FAQ
|
2
2
|
|
3
|
-
|
3
|
+
== General questions
|
4
4
|
|
5
|
-
Q
|
5
|
+
*Q* Can I use Rails 3 migrations with Repertoire Faceting?
|
6
6
|
|
7
|
-
A. Put the following line in environment.rb:
|
7
|
+
*A* In general, yes. However, Rails' developers recommend you use the database's native dump format rather than schema.rb. Put the following line in environment.rb:
|
8
8
|
|
9
|
-
|
9
|
+
config.active_record.schema_format = :sql
|
10
10
|
|
11
11
|
|
12
|
-
|
12
|
+
== About facet indexing and the signature SQL type
|
13
13
|
|
14
|
-
Q
|
14
|
+
*Q* What's the scalability of this thing?
|
15
15
|
|
16
|
-
A
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
*A* Up to about 500,000 items, supposing 6-8 simultaneous facets with domains anywhere from 2-100 values. In other words, beyond the size of most commonly available datasets. See the citizens example in the specs directory & example faceting app. It has been tested with up to 1,000,000 items, but this requires unix configuration to give Postgresql lots of shared memory.
|
17
|
+
|
18
|
+
|
19
|
+
*Q* My facets are empty.
|
20
|
+
|
21
|
+
*A* Make sure the facet indices aren't empty. Running '<model>.update_indexed_facets([])' from the console will drop them all.
|
22
|
+
|
23
|
+
|
24
|
+
*Q* Can I facet over multiple models?
|
25
|
+
|
26
|
+
*A* Not currently. However, this may be possible using an ActiveRecord polymorphic relation on the main model.
|
20
27
|
|
21
28
|
|
22
|
-
Q
|
29
|
+
*Q* Why a new native PostgreSQL type?
|
23
30
|
|
24
|
-
A.
|
31
|
+
*A* As of PostgreSQL 8.4, there is no support for population counts in either blobs or bitstrings. Neither of these built-in types provides both the bitset and I/O functions required for faceting.
|
25
32
|
|
26
33
|
|
34
|
+
== About the ajax faceting widgets
|
27
35
|
|
28
|
-
= About the ajax faceting widgets =
|
29
36
|
|
30
|
-
Q
|
37
|
+
*Q* Rails 3 is sending JSON data in a format that my javascript widgets don't understand.
|
31
38
|
|
32
|
-
A
|
33
|
-
prototype.js and rails.js from the javascripts directory, and delete the <%= javascript_include_tag :defaults %>
|
34
|
-
line from application.html.erb.
|
39
|
+
*A* Put the following line in config/application.rb:
|
35
40
|
|
36
|
-
|
41
|
+
config.active_record.include_root_in_json = false
|
37
42
|
|
38
|
-
|
39
|
-
|
43
|
+
|
44
|
+
*Q* A web page from the default Rails app refuses to load the faceting widgets.
|
45
|
+
|
46
|
+
*A* Repertoire Faceting widgets are based on JQuery, which is incompatible with Prototype. You should remove prototype.js and rails.js from the javascripts directory, and delete the <%= javascript_include_tag :defaults %> line from application.html.erb.
|
47
|
+
|
48
|
+
|
49
|
+
*Q* How do I send page-specific data (for example, a search field) to the webservice with the facet widgets' data?
|
50
|
+
|
51
|
+
*A* If you provide a function to the facet_context plugin, it will merge the params you return before dispatching to the webservice, e.g.
|
40
52
|
|
41
53
|
$('#invoices').facet_context(function() {
|
42
54
|
return {
|
@@ -45,16 +57,13 @@ A. If you provide a function to the facet_context plugin, it will merge the para
|
|
45
57
|
});
|
46
58
|
|
47
59
|
|
48
|
-
Q
|
60
|
+
*Q* I want to change the default options for all widgets of a given class.
|
49
61
|
|
50
|
-
A
|
51
|
-
view code.
|
62
|
+
*A* See the syntax for defining jquery plugins - you can alter the defaults for all widgets by reassigning them in your view code.
|
52
63
|
|
53
|
-
Q
|
64
|
+
*Q* How do I make one-time, minor changes to the behaviour of a widget? For example, I want to add a control.
|
54
65
|
|
55
|
-
A
|
56
|
-
widget's jquery element and to the widget javascript object. Use jquery to add your control's markup, then
|
57
|
-
register an event handler to add its behaviour. For example, this injector adds a clear-all button in the title:
|
66
|
+
*A* Use the inject option, which is part of the base functionality. Your injector function receives a reference to the widget's jquery element and to the widget javascript object. Use jquery to add your control's markup, then register an event handler to add its behaviour. For example, this injector adds a clear-all button in the title:
|
58
67
|
|
59
68
|
$('#genre').facet({
|
60
69
|
injectors: {
|
@@ -69,20 +78,17 @@ A. Use the inject option, which is part of the base functionality. Your injecto
|
|
69
78
|
}
|
70
79
|
});
|
71
80
|
|
72
|
-
|
73
|
-
receive a single argument 'self' for the widget object, and 'this' for the matched DOM element.
|
74
|
-
|
75
|
-
Note the syntax used to identify a handler's event and dom element: '<event.namespace>!<target>'. Both event and namespace
|
76
|
-
are optional - leave them out to register a click handler with a unique namespace.
|
77
|
-
|
78
|
-
In injectors and handlers, you have access to the complete faceting widget API (state, refinements, toggle, is_selected, etc.).
|
79
|
-
You can basically build a new widget, if you need to. See the documentation for the faceting_widget class for details.
|
81
|
+
The injector adds markup for the control at the specific jquery selector, and the handler receives events on that markup. Both receive a single argument 'self' for the widget object, and 'this' for the matched DOM element.
|
80
82
|
|
83
|
+
Note the syntax used to identify a handler's event and dom element: '<event.namespace>!<target>'. Both event and namespace are optional - leave them out to register a click handler with a unique namespace.
|
81
84
|
|
82
|
-
|
85
|
+
In injectors and handlers, you have access to the complete faceting widget API (state, refinements, toggle, is_selected, etc.). You can basically build a new widget, if you need to. See the documentation for the faceting_widget class for details.
|
86
|
+
|
87
|
+
|
88
|
+
*Q* My additonal control needs to send data back to the webservice too.
|
89
|
+
|
90
|
+
*A* You can pre-process the entire context's state before it's sent to the webservice by update():
|
83
91
|
|
84
|
-
A. You can pre-process the entire context's state before it's sent to the webservice by update():
|
85
|
-
|
86
92
|
var min = 5;
|
87
93
|
$('#genre').facet({
|
88
94
|
injectors: { ... },
|
@@ -91,46 +97,42 @@ A. You can pre-process the entire context's state before it's sent to the webser
|
|
91
97
|
}
|
92
98
|
|
93
99
|
|
94
|
-
Q
|
100
|
+
*Q* How do I subclass an existing widget, so I can reuse my changes repeatedly?
|
95
101
|
|
96
|
-
A
|
97
|
-
results widget for the simplest possible example, and nested_facet for a real-world example that extends the default facet
|
98
|
-
widget. At a bare minimum, you will over-ride the render() method, and possibly the update() method too. Here's a 'hello
|
99
|
-
world' that extends the default facet count widget:
|
102
|
+
*A* Basically you define a new widget class and move your injectors and handlers (above) into the appropriate places. See the results widget for the simplest possible example, and nested_facet for a real-world example that extends the default facet widget. At a bare minimum, you will over-ride the render() method, and possibly the update() method too. Here is a 'hello world' that extends the default facet count widget:
|
100
103
|
|
101
|
-
var hello_world = function($elem, options) {
|
102
|
-
|
103
|
-
|
104
|
+
var hello_world = function($elem, options) {
|
105
|
+
/* declare superclass */
|
106
|
+
var self = repertoire.facet($elem, options);
|
104
107
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
108
|
+
/* handlers */
|
109
|
+
handler('.hello', function() {
|
110
|
+
alert('hello, world!');
|
111
|
+
});
|
112
|
+
|
113
|
+
/* injectors */
|
114
|
+
var $template_fn = self.render;
|
115
|
+
self.render = function(data) {
|
116
|
+
var $markup = $template_fn(data);
|
117
|
+
$markup.find('.title .controls').append('<div class='hello'>click me!</div');
|
118
|
+
return $markup;
|
119
|
+
}
|
117
120
|
|
118
|
-
|
119
|
-
}
|
121
|
+
return self;
|
122
|
+
}
|
120
123
|
|
121
124
|
|
122
|
-
Q
|
125
|
+
*Q* That's great, but how do I turn it into a jquery plugin I can actually use?
|
123
126
|
|
124
|
-
A
|
125
|
-
options defaults for the widget.
|
127
|
+
*A* Call the plugin method and assign it to a variable in the jquery prototype. If provided, the line following sets universal options defaults for the widget.
|
126
128
|
|
127
129
|
$.fn.hello_world = repertoire.plugin(hello_world);
|
128
130
|
$.fn.hello_world.defaults = { ... }; // put default options here
|
129
131
|
|
130
132
|
|
131
|
-
Q
|
133
|
+
*Q* How do these widgets relate to each other?
|
132
134
|
|
133
|
-
A
|
135
|
+
*A* Here is the class hierarchy:
|
134
136
|
|
135
137
|
facet_widget (abstract)
|
136
138
|
+--- facet
|
@@ -138,39 +140,34 @@ A. Here is the class hierarchy:
|
|
138
140
|
+--- results
|
139
141
|
|
140
142
|
|
141
|
-
Q
|
143
|
+
*Q* In my widget or handler, how do I override an event handler from the superclass?
|
142
144
|
|
143
|
-
A
|
144
|
-
in the default facet widget is registered under the jquery event/namespace 'click.toggle_value'. To over-ride:
|
145
|
+
*A* Register another handler to the exact same event and namespace. E.g. toggling selection for facet value counts in the default facet widget is registered under the jquery event/namespace 'click.toggle_value'. To over-ride:
|
145
146
|
|
146
|
-
... [ in widget's constructor function ]
|
147
|
+
... [ in widget's constructor function ]
|
147
148
|
|
148
|
-
self.handler('click.toggle_value!.facet .value', function() {
|
149
|
-
|
150
|
-
}
|
151
|
-
...
|
149
|
+
self.handler('click.toggle_value!.facet .value', function() {
|
150
|
+
... redefined event handler
|
151
|
+
}
|
152
|
+
...
|
152
153
|
|
153
154
|
|
154
|
-
Q
|
155
|
-
use a different webservice.
|
155
|
+
*Q* My widget needs to send additional data to the webservice, pre-process the state, compute my own query string, or use a different webservice.
|
156
156
|
|
157
|
-
A
|
158
|
-
data that affects only the current widget, store it in a private variable and add it in update(). (2) if the additional
|
159
|
-
data affects all otherfacets, store it in the structure returned by self.state() and make sure the other widgets/webservices
|
160
|
-
can process it correctly.
|
161
|
-
|
162
|
-
|
163
|
-
Q. What Javascript OOP convention is this?
|
157
|
+
*A* You can over-ride self.update() to alter the webservice ajax call or replace it with your own. (a) if sending additional data that affects only the current widget, store it in a private variable and add it in update(). (b) if the additional data affects all other facets, store it in the structure returned by self.state() and make sure the other widgets/webservices can process it correctly.
|
164
158
|
|
165
|
-
A. It's based on section 5.4, "Functional Inheritance" of Douglas Crockford, "Javascript: The Good Parts."
|
166
159
|
|
160
|
+
*Q* What Javascript OOP convention is this?
|
167
161
|
|
168
|
-
|
162
|
+
*A* It's based on section 5.4, "Functional Inheritance" of Douglas Crockford, "Javascript: The Good Parts."
|
169
163
|
|
170
|
-
A. $foo is a jquery object, e.g. var $foo = $('.foo')
|
171
|
-
self is the object you're currently defining (as opposed to the one it inherits from, javascript's 'this', or its dom view)
|
172
|
-
|
173
|
-
|
174
|
-
Q. Why not support the metadata jquery plugin? Why not automatically turn all elements with a 'facet' class into facet widgets?
|
175
164
|
|
176
|
-
|
165
|
+
*Q* Explain the naming conventions.
|
166
|
+
|
167
|
+
*A* $foo is a jquery object, e.g. var $foo = $('.foo')
|
168
|
+
self is the object you're currently defining (as opposed to the one it inherits from, javascript's 'this', or its dom view)
|
169
|
+
|
170
|
+
|
171
|
+
*Q* Why not support the metadata jquery plugin? Why not automatically turn all elements with a 'facet' class into facet widgets?
|
172
|
+
|
173
|
+
*A* Possibly. It needs some thought.
|
data/INSTALL
CHANGED
@@ -1,49 +1,53 @@
|
|
1
1
|
=== Installing Repertoire Faceting
|
2
2
|
|
3
|
-
|
3
|
+
N.B. Repertoire Faceting requires Rails 3.0+, Ruby 1.9.2+, and JQuery 1.3.2+.
|
4
|
+
|
5
|
+
== Short version.
|
6
|
+
|
7
|
+
(You need a working Rails 3 app, with a model, controller, and a partial to show the model)
|
4
8
|
|
5
9
|
{ in Gemfile }
|
6
|
-
gem 'repertoire-faceting'
|
10
|
+
gem 'repertoire-faceting' // 1
|
7
11
|
|
8
12
|
{ install native bitset extensions }
|
9
13
|
$ bundle install
|
10
|
-
$ rake db:faceting:build
|
14
|
+
$ rake db:faceting:build { provide sudo your password }
|
11
15
|
$ rake db:faceting:load
|
12
16
|
|
13
17
|
{ in ./app/models/some_model.rb }
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
class SomeModel
|
19
|
+
include Repertoire::Faceting::Model // 2
|
20
|
+
facet :some_column // 3
|
21
|
+
end
|
18
22
|
|
19
23
|
{ in ./app/controllers/some_controller]
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
class SomeController
|
25
|
+
include Repertoire::Faceting::Controller // 4
|
26
|
+
def base; return SomeModel; end // 5
|
27
|
+
end
|
28
|
+
|
25
29
|
{ in ./config/routes.rb }
|
26
30
|
SomeApp::Application.routes.draw do
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
faceting_for :some_model // 6
|
32
|
+
end
|
33
|
+
|
34
|
+
{ in ./public/javascripts/application.js }
|
35
|
+
//= require <rep.faceting> // 7
|
32
36
|
|
33
37
|
{ in ./app/views/some_controller/index.html.erb }
|
34
38
|
<script language="javascript">
|
35
39
|
$().ready(function() {
|
36
|
-
$('#paintings').facet_context();
|
37
|
-
$('.facet').facet();
|
38
|
-
$('#results').results();
|
40
|
+
$('#paintings').facet_context(); // 8
|
41
|
+
$('.facet').facet(); // 9
|
42
|
+
$('#results').results(); // 10
|
39
43
|
});
|
40
44
|
</script>
|
41
|
-
<div id='paintings'>
|
42
|
-
<div id='genre' class='facet'></div>
|
43
|
-
<div id='results'></div>
|
45
|
+
<div id='paintings'> // 11
|
46
|
+
<div id='genre' class='facet'></div> // 12
|
47
|
+
<div id='results'></div> // 13
|
44
48
|
</div>
|
45
49
|
|
46
|
-
|
50
|
+
... that's a complete faceted browser in only 13 new lines of code in your app!
|
47
51
|
|
48
52
|
In production, you will want to compress the javascript facet widgets:
|
49
53
|
|
@@ -62,168 +66,176 @@
|
|
62
66
|
|
63
67
|
Start with a working Rails 3 application with a PostgreSQL database.
|
64
68
|
|
65
|
-
* Require repertoire-faceting in Gemfile.
|
66
|
-
|
67
|
-
gem 'repertoire-faceting'
|
68
|
-
|
69
|
-
* Make sure you use Rails version 3.0.2+, which adopted Arel 2.0.1. If necessary
|
70
|
-
you can pull rails, arel, and rack from git.
|
71
|
-
|
72
|
-
gem 'rails', :git => 'git://github.com/rails/rails.git'
|
73
|
-
gem 'arel', :git => 'git://github.com/rails/arel.git'
|
74
|
-
gem "rack", :git => "git://github.com/rack/rack.git"
|
75
|
-
|
76
|
-
* At the command line, bundle everything into your application:
|
77
|
-
|
78
|
-
$ bundle install
|
79
|
-
|
80
|
-
* From your application root, build and install the repertoire-faceting native
|
81
|
-
extensions to PostgreSQL. These provide a bitwise signature type used to
|
82
|
-
index and count facets.
|
83
|
-
|
84
|
-
$ rake db:faceting:build { sudo will prompt you for your password }
|
85
|
-
|
86
|
-
* Load the extension into your local application database. This ensures the
|
87
|
-
plpgsql language is installed, and loads (or re-loads) the new bitset signature
|
88
|
-
type.
|
89
|
-
|
90
|
-
$ rake db:faceting:load
|
91
|
-
|
92
|
-
You can confirm the module is installed as follows.
|
93
|
-
|
94
|
-
$ psql -c "SELECT count('101010101'::signature);" -U<username> <database>
|
69
|
+
* Require repertoire-faceting in Gemfile.
|
95
70
|
|
96
|
-
|
97
|
-
existing database column. (See the README for complete configuration options
|
98
|
-
for facets.)
|
71
|
+
gem 'repertoire-faceting'
|
99
72
|
|
100
|
-
|
101
|
-
|
102
|
-
include Repertoire::Faceting::Model
|
103
|
-
facet :genre
|
104
|
-
end
|
73
|
+
* Make sure you use Rails version 3.0.2+, which adopted Arel 2.0.1. If necessary
|
74
|
+
you can pull rails, arel, and rack from git.
|
105
75
|
|
106
|
-
|
76
|
+
gem 'rails', :git => 'git://github.com/rails/rails.git'
|
77
|
+
gem 'arel', :git => 'git://github.com/rails/arel.git'
|
78
|
+
gem "rack", :git => "git://github.com/rack/rack.git"
|
107
79
|
|
108
|
-
|
109
|
-
> Painting.count(:genre)
|
110
|
-
=> {"Impressionist"=>2, "Medieval"=>2}
|
111
|
-
> Painting.refine(:genre => 'Impressionist')
|
112
|
-
=> [#<Painting id: 1, title: "Moonlight Shimmers", painter: "Monet", genre: "Impressionist">,
|
113
|
-
#<Painting id: 2, title: "Nude Lunch in Garden", painter: "Manet", genre: "Impressionist">]
|
80
|
+
* At the command line, bundle everything into your application:
|
114
81
|
|
115
|
-
|
82
|
+
$ bundle install
|
116
83
|
|
117
|
-
|
118
|
-
|
84
|
+
* From your application root, build and install the repertoire-faceting native
|
85
|
+
extensions to PostgreSQL. These provide a bitwise signature type used to
|
86
|
+
index and count facets.
|
119
87
|
|
120
|
-
|
88
|
+
$ rake db:faceting:build { sudo will prompt you for your password }
|
121
89
|
|
122
|
-
|
123
|
-
|
124
|
-
|
90
|
+
* Load the extension into your local application database. This ensures the
|
91
|
+
plpgsql language is installed, and loads (or re-loads) the new bitset signature
|
92
|
+
type.
|
125
93
|
|
126
|
-
|
127
|
-
|
128
|
-
Painting.where(["title like ?", search])
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
* Add faceting routes to your application.
|
133
|
-
|
134
|
-
{ ./config/routes.rb }
|
135
|
-
|
136
|
-
PaintingsApp::Application.routes.draw do
|
137
|
-
faceting_for :paintings # NB must be BEFORE any resources!
|
138
|
-
...
|
139
|
-
end
|
140
|
-
|
141
|
-
Confirm they load:
|
142
|
-
|
143
|
-
$ rake routes
|
144
|
-
...
|
145
|
-
/paintings/counts/:facet(.:format) {:controller=>"paintings", :action=>"counts"}
|
146
|
-
paintings_results /paintings/results(.:format) {:controller=>"paintings", :action=>"results"}
|
147
|
-
...
|
148
|
-
|
149
|
-
* Load the javascript facet widgets in your main javascript file. The
|
150
|
-
repertoire-assets subsystem will locate the widgets in your application's
|
151
|
-
rubygems, and load them as appropriate.
|
152
|
-
|
153
|
-
{ ./public/javascripts/application.js }
|
154
|
-
...
|
155
|
-
//= require <rep.faceting>
|
156
|
-
...
|
157
|
-
|
158
|
-
N.B. Repertoire Faceting widgets are based on JQuery, which is incompatible
|
159
|
-
with Prototype. If you have not already done so, you should remove
|
160
|
-
prototype.js and rails.js from the javascripts directory, and delete the
|
161
|
-
"<%= javascript_include_tag :defaults %>" line from application.html.erb.
|
162
|
-
|
163
|
-
* Add facet count and result widgets to your HTML page. The facet context div
|
164
|
-
collects widgets that affect the same query together. (For complete options,
|
165
|
-
see the README )
|
166
|
-
|
167
|
-
{ ./app/views/paintings/index.html.erb }
|
168
|
-
|
169
|
-
<script language="javascript">
|
170
|
-
$().ready(function() {
|
171
|
-
$('#paintings').facet_context();
|
172
|
-
$('.facet').facet();
|
173
|
-
$('#results').results();
|
174
|
-
});
|
175
|
-
</script>
|
176
|
-
<div id='paintings'>
|
177
|
-
<div id='genre' class='facet'></div>
|
178
|
-
<div id='results'></div>
|
179
|
-
</div>
|
180
|
-
|
181
|
-
* If you don't already have one, create a partial for displaying your model in
|
182
|
-
results lists.
|
183
|
-
|
184
|
-
{ ./app/views/paintings/_painting.html.erb }
|
185
|
-
|
186
|
-
<div class='painting' style='width:235px; margin-bottom:5px; padding:2px; border:dotted 1px;'>
|
187
|
-
<div>Title: <%= painting.title %></div>
|
188
|
-
<div>Painter: <%= painting.painter %></div>
|
189
|
-
<div>Genre: <%= painting.genre %></div>
|
190
|
-
</div>
|
191
|
-
|
192
|
-
* [ Optional ] Configure the repertoire-assets module that loads the javascript
|
193
|
-
faceting widgets to compress the widget code in production.
|
194
|
-
|
195
|
-
{ ./config/environments/production.rb }
|
196
|
-
|
197
|
-
PaintingsApp::Application.configure do
|
198
|
-
...
|
199
|
-
config.repertoire_assets.compress = true
|
200
|
-
...
|
201
|
-
end
|
202
|
-
|
203
|
-
* [ Optional ] Add bitset indexes to some facets on your model. The module will
|
204
|
-
automatically use facet indexes when they are available. Facet indexes scale
|
205
|
-
out of the box to over a million model items, and require no additional
|
206
|
-
configuration.
|
207
|
-
|
208
|
-
$ rails generate migration AddFacetIndex
|
94
|
+
$ createlang plpgsql -U<username> <database>
|
95
|
+
$ rake db:faceting:load
|
209
96
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
97
|
+
Or, if you prefer to use migrations create one with the following contents:
|
98
|
+
|
99
|
+
....
|
100
|
+
def self.up
|
101
|
+
load_faceting # unload_faceting is the reverse
|
102
|
+
end
|
103
|
+
|
104
|
+
Before proceeding, you can confirm the module is installed as follows.
|
105
|
+
|
106
|
+
$ psql -c "SELECT count('101010101'::signature);" -U<username> <database>
|
107
|
+
|
108
|
+
* Install the faceting mixin in your Rails model and declare a facet on an
|
109
|
+
existing database column. (See the README for complete configuration options
|
110
|
+
for facets.)
|
111
|
+
|
112
|
+
{ ./app/models/painting.rb }
|
113
|
+
class Painting
|
114
|
+
include Repertoire::Faceting::Model
|
115
|
+
facet :genre
|
116
|
+
end
|
117
|
+
|
118
|
+
* Test doing facet count and result queries:
|
119
|
+
|
120
|
+
$ rails c
|
121
|
+
> Painting.count(:genre)
|
122
|
+
=> {"Impressionist"=>2, "Medieval"=>2}
|
123
|
+
> Painting.refine(:genre => 'Impressionist')
|
124
|
+
=> [#<Painting id: 1, title: "Moonlight Shimmers", painter: "Monet", genre: "Impressionist">,
|
125
|
+
#<Painting id: 2, title: "Nude Lunch in Garden", painter: "Manet", genre: "Impressionist">]
|
126
|
+
|
127
|
+
Or, with a base query as well:
|
128
|
+
|
129
|
+
> Painting.where(["title like ?", 'Moon%']).count(:genre)
|
130
|
+
=> {"Impressionist"=>1}
|
131
|
+
|
132
|
+
* Add faceting webservices to your controller and define base() to indicate which model to base queries on
|
133
|
+
|
134
|
+
{ ./app/controllers/paintings_controller }
|
135
|
+
class PaintingsController
|
136
|
+
include Repertoire::Faceting::Controller
|
137
|
+
|
138
|
+
def base
|
139
|
+
search = "%#{params[:search]}%"
|
140
|
+
Painting.where(["title like ?", search])
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
* Add faceting routes to your application.
|
145
|
+
|
146
|
+
{ ./config/routes.rb }
|
147
|
+
|
148
|
+
PaintingsApp::Application.routes.draw do
|
149
|
+
faceting_for :paintings # NB must be BEFORE any resources!
|
150
|
+
...
|
151
|
+
end
|
152
|
+
|
153
|
+
Confirm they load:
|
154
|
+
|
155
|
+
$ rake routes
|
156
|
+
...
|
157
|
+
/paintings/counts/:facet(.:format) {:controller=>"paintings", :action=>"counts"}
|
158
|
+
paintings_results /paintings/results(.:format) {:controller=>"paintings", :action=>"results"}
|
159
|
+
...
|
160
|
+
|
161
|
+
* Load the javascript facet widgets in your main javascript file. The
|
162
|
+
repertoire-assets subsystem will locate the widgets in your application's
|
163
|
+
rubygems, and load them as appropriate.
|
164
|
+
|
165
|
+
{ ./public/javascripts/application.js }
|
166
|
+
...
|
167
|
+
//= require <rep.faceting>
|
168
|
+
...
|
169
|
+
|
170
|
+
N.B. Repertoire Faceting widgets are based on JQuery, which is incompatible
|
171
|
+
with Prototype. If you have not already done so, you should remove
|
172
|
+
prototype.js and rails.js from the javascripts directory, and delete the
|
173
|
+
"<%= javascript_include_tag :defaults %>" line from application.html.erb.
|
174
|
+
|
175
|
+
* Add facet count and result widgets to your HTML page. The facet context div
|
176
|
+
collects widgets that affect the same query together. (For complete options,
|
177
|
+
see the README )
|
178
|
+
|
179
|
+
{ ./app/views/paintings/index.html.erb }
|
180
|
+
|
181
|
+
<script language="javascript">
|
182
|
+
$().ready(function() {
|
183
|
+
$('#paintings').facet_context();
|
184
|
+
$('.facet').facet();
|
185
|
+
$('#results').results();
|
186
|
+
});
|
187
|
+
</script>
|
188
|
+
<div id='paintings'>
|
189
|
+
<div id='genre' class='facet'></div>
|
190
|
+
<div id='results'></div>
|
191
|
+
</div>
|
192
|
+
|
193
|
+
* If you don't already have one, create a partial for displaying your model in
|
194
|
+
results lists.
|
195
|
+
|
196
|
+
{ ./app/views/paintings/_painting.html.erb }
|
197
|
+
|
198
|
+
<div class='painting' style='width:235px; margin-bottom:5px; padding:2px; border:dotted 1px;'>
|
199
|
+
<div>Title: <%= painting.title %></div>
|
200
|
+
<div>Painter: <%= painting.painter %></div>
|
201
|
+
<div>Genre: <%= painting.genre %></div>
|
202
|
+
</div>
|
203
|
+
|
204
|
+
* [ Optional ] Configure the repertoire-assets module that loads the javascript
|
205
|
+
faceting widgets to compress the widget code in production.
|
206
|
+
|
207
|
+
{ ./config/environments/production.rb }
|
208
|
+
|
209
|
+
PaintingsApp::Application.configure do
|
210
|
+
...
|
211
|
+
config.repertoire_assets.compress = true
|
212
|
+
...
|
213
|
+
end
|
214
|
+
|
215
|
+
* [ Optional ] Add bitset indexes to some facets on your model. The module will
|
216
|
+
automatically use facet indexes when they are available. Facet indexes scale
|
217
|
+
out of the box to over a million model items, and require no additional
|
218
|
+
configuration.
|
219
|
+
|
220
|
+
$ rails generate migration AddFacetIndex
|
221
|
+
|
222
|
+
{ ./db/migrate/<your date>add_facet_index.rb }
|
223
|
+
class AddFacetIndex < ActiveRecord::Migration
|
224
|
+
def self.up
|
225
|
+
Painting.update_indexed_facets([:genre])
|
226
|
+
end
|
215
227
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
228
|
+
def self.down
|
229
|
+
Painting.update_indexed_facets
|
230
|
+
end
|
231
|
+
end
|
220
232
|
|
221
|
-
* [ Optional ] Periodically update indexes via a crontab task.
|
233
|
+
* [ Optional ] Periodically update indexes via a crontab task.
|
222
234
|
|
223
|
-
|
235
|
+
{ ./lib/tasks/update_facets.rake }
|
224
236
|
|
225
|
-
|
226
|
-
|
227
|
-
|
237
|
+
task :reindex => :environment do
|
238
|
+
Painting.update_indexed_facets
|
239
|
+
end
|
228
240
|
|
229
|
-
|
241
|
+
... And then configure crontab to execute 'rake reindex' at appropriate intervals.
|