wice_grid 3.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG +412 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +1179 -0
  5. data/Rakefile +42 -0
  6. data/SAVED_QUERIES_HOWTO.rdoc +123 -0
  7. data/VERSION +1 -0
  8. data/lib/generators/wice_grid/templates/calendarview.css +107 -0
  9. data/lib/generators/wice_grid/templates/calendarview.js +1168 -0
  10. data/lib/generators/wice_grid/templates/icons/arrow_down.gif +0 -0
  11. data/lib/generators/wice_grid/templates/icons/arrow_up.gif +0 -0
  12. data/lib/generators/wice_grid/templates/icons/calendar_view_month.png +0 -0
  13. data/lib/generators/wice_grid/templates/icons/delete.png +0 -0
  14. data/lib/generators/wice_grid/templates/icons/expand.png +0 -0
  15. data/lib/generators/wice_grid/templates/icons/page_white_excel.png +0 -0
  16. data/lib/generators/wice_grid/templates/icons/page_white_find.png +0 -0
  17. data/lib/generators/wice_grid/templates/icons/table.png +0 -0
  18. data/lib/generators/wice_grid/templates/icons/table_refresh.png +0 -0
  19. data/lib/generators/wice_grid/templates/icons/tick_all.png +0 -0
  20. data/lib/generators/wice_grid/templates/icons/untick_all.png +0 -0
  21. data/lib/generators/wice_grid/templates/wice_grid.css +173 -0
  22. data/lib/generators/wice_grid/templates/wice_grid.yml +279 -0
  23. data/lib/generators/wice_grid/templates/wice_grid_config.rb +154 -0
  24. data/lib/generators/wice_grid/templates/wice_grid_jquery.js +161 -0
  25. data/lib/generators/wice_grid/templates/wice_grid_prototype.js +153 -0
  26. data/lib/generators/wice_grid/wice_grid_assets_jquery_generator.rb +32 -0
  27. data/lib/generators/wice_grid/wice_grid_assets_prototype_generator.rb +34 -0
  28. data/lib/grid_output_buffer.rb +52 -0
  29. data/lib/grid_renderer.rb +535 -0
  30. data/lib/helpers/js_calendar_helpers.rb +183 -0
  31. data/lib/helpers/wice_grid_misc_view_helpers.rb +113 -0
  32. data/lib/helpers/wice_grid_serialized_queries_view_helpers.rb +91 -0
  33. data/lib/helpers/wice_grid_view_helpers.rb +781 -0
  34. data/lib/js_adaptors/jquery_adaptor.rb +145 -0
  35. data/lib/js_adaptors/js_adaptor.rb +12 -0
  36. data/lib/js_adaptors/prototype_adaptor.rb +168 -0
  37. data/lib/table_column_matrix.rb +51 -0
  38. data/lib/tasks/wice_grid_tasks.rake +28 -0
  39. data/lib/view_columns.rb +486 -0
  40. data/lib/views/create.rjs +13 -0
  41. data/lib/views/create_jq.rjs +31 -0
  42. data/lib/views/delete.rjs +12 -0
  43. data/lib/views/delete_jq.rjs +26 -0
  44. data/lib/wice_grid.rb +827 -0
  45. data/lib/wice_grid_controller.rb +165 -0
  46. data/lib/wice_grid_core_ext.rb +179 -0
  47. data/lib/wice_grid_misc.rb +98 -0
  48. data/lib/wice_grid_serialized_queries_controller.rb +86 -0
  49. data/lib/wice_grid_serialized_query.rb +15 -0
  50. data/lib/wice_grid_spreadsheet.rb +33 -0
  51. data/test/.gitignore +2 -0
  52. data/test/database.yml +21 -0
  53. data/test/schema.rb +33 -0
  54. data/test/test_helper.rb +89 -0
  55. data/test/views/projects_and_people_grid.html.erb +12 -0
  56. data/test/views/projects_and_people_grid_invalid.html.erb +12 -0
  57. data/test/views/simple_projects_grid.html.erb +9 -0
  58. data/test/wice_grid_core_ext_test.rb +183 -0
  59. data/test/wice_grid_functional_test.rb +68 -0
  60. data/test/wice_grid_misc_test.rb +41 -0
  61. data/test/wice_grid_test.rb +42 -0
  62. data/test/wice_grid_view_helper_test.rb +12 -0
  63. data/wice_grid.gemspec +111 -0
  64. metadata +153 -0
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .DS_Store
data/CHANGELOG ADDED
@@ -0,0 +1,412 @@
1
+ 0.6
2
+
3
+ wice_grid_custom_filter_params used to be a view helper, not it is also accessible from the controller, to be used in cases like redirect_to(my_resource_path(wice_grid_custom_filter_params(...)))
4
+
5
+ auto reloading filters
6
+
7
+ helper export_to_csv_javascript to create custom CSV buttons
8
+
9
+ option :hide_csv_button to hide the default CSV export button
10
+
11
+ Method WiceGrid#selected_records and parameter :after were a bit of a mess and have been substituted by
12
+
13
+ * WiceGrid#current_page_records returning records on the current page
14
+ * WiceGrid#all_pages_records returning records browsable throughout all pages
15
+ * :with_paginated_resultset - callback to process records on the current page
16
+ * :with_resultset - callback to process records browsable throughout all pages
17
+
18
+ Compliant with Rails 1.2.8 with or without rails_xss and erubis
19
+
20
+ Ruby 1.9.1 compliance
21
+
22
+ Dropdowns generated with :custom_filter => :auto and :custom_filter => [method chain] are now ordered by option labels
23
+
24
+ how_filters => false is the same as :show_filters => :no and :show_filters => true is the same as :show_filters => :always
25
+
26
+ action_column - Adds a column with checkboxes for each record.
27
+ Useful for actions with multiple records, for example, delete
28
+ the selected records.
29
+
30
+ using merge_conditions to merge conditions :)
31
+
32
+ WiceGrid is now compatible with the new Rails XSS behavior which
33
+ will be the default in Rails 3.0 and can be used in Rails 2.3.5
34
+ using the rails_xss plugin.
35
+ Read http://github.com/nzkoz/rails_xss for more
36
+
37
+ wice_grid_custom_filter_params
38
+
39
+ support for with_scope and with_exclusive_scope
40
+
41
+ :total_entries parameter added to initialize_grid (will_paginate)
42
+
43
+ Localization
44
+
45
+ assert_keys wherever possible
46
+
47
+ == 0.5
48
+
49
+ Today "WiceGrid":http://leikind.org/pages/wicegrid has reached its next level of maturity and was awarded the tag of version 0.5.
50
+
51
+ This version of WiceGrid is accompanied by an application called _WiceGrid Examples_ running "online":http://grid.leikind.org/ and with source code available on "GitHub":http://github.com/leikind/wice_grid_examples.
52
+
53
+ Here's a list of changes as compared with "version 0.4":https://blog.wice.eu/2009/7/6/moving-to-github-and-wicegrid-version-0-4 :
54
+
55
+ h4. selected_records
56
+
57
+ Method @selected_records@ of WiceGrid instances allows to access the list of all records of the current selection throughout all pages in the context of a view:
58
+
59
+ --- RHTML
60
+ <%= grid(@tasks_grid) do |g|
61
+ ...
62
+ end -%>
63
+
64
+ <% selected = @tasks_grid.selected_records %>
65
+ <p><%= selected.size %> records selected: <%= selected.map(&:id).to_sentence %></p>
66
+ ---
67
+
68
+ "See an online example":http://grid.leikind.org/integration_with_application_view
69
+
70
+ h4. placement of filter related icons
71
+
72
+ A change in placement of filter related icons (filter icon, reset icon, show/hide icon): if the last column doesn't have any filter or a column name, icons will be placed in the header of this column, otherwise it falls back to the usual behavior when an additional table column is added. To change the behavior back to the old style, set @Wice::Defaults::REUSE_LAST_COLUMN_FOR_FILTER_ICONS@ to @false@ in the configuration file.
73
+
74
+ "See an online example":http://grid.leikind.org/custom_filters2
75
+
76
+
77
+ h4. wice_grid_assets generator
78
+
79
+ Copying asset files (images, css, js, and the configuration file) is now done by a plugin generator, not rake tasks:
80
+
81
+ ---
82
+ ./script/generate wice_grid_assets
83
+ ---
84
+
85
+ h4. blank slate
86
+
87
+ Blank slate feature: it is now possible to replace the grid with some alternative view if no filters are active and there are no records to render:
88
+
89
+ --- RHTML
90
+ <%= grid(@grid) do |g|
91
+
92
+ g.blank_slate do
93
+ "There are no records"
94
+ end
95
+
96
+ g.column do |product|
97
+ ...
98
+ end
99
+ end -%>
100
+ ---
101
+
102
+ There are also two alternative three ways to do it:
103
+
104
+ --- Ruby
105
+ g.blank_slate "some text to be rendered"
106
+ ---
107
+ and
108
+ --- Ruby
109
+ g.blank_slate :partial => "partial_name"
110
+ ---
111
+
112
+ "See an online example":http://grid.leikind.org/no_records
113
+
114
+ h4. custom filters with symbols
115
+
116
+ Improvement to custom filters, namely to
117
+ --- Ruby
118
+ :custom_filter => :symbol
119
+ ---
120
+ and
121
+ --- Ruby
122
+ :custom_filter => [:symbol1, :symbol2, :symbol3]
123
+ ---
124
+
125
+ Now, if the last method returns an array of 2 elements, the first element becomes the select option label and the second - the select option value (usually @id@).
126
+
127
+ Before this change the value returned by the method had been used for both the value and the label of the select option.
128
+
129
+ "See an online example":http://grid.leikind.org/custom_filters3
130
+
131
+ h4. custom filters and NULL
132
+
133
+ Values @null@ and @not null@ in a generated custom filter dropdown are treated specially, as SQL @null@ statement and not as strings. Value @null@ is transformed into SQL condition @IS NULL@, and @not null@ into @IS NOT NULL@ .
134
+
135
+ Thus, if in a filter defined by
136
+
137
+ --- Ruby
138
+ :custom_filter => {'No' => 'null', 'Yes' => 'not null', '1' => 1, '2' => '2', '3' => '3'}
139
+ ---
140
+ values @1@, @2@ and @'No'@ are selected (in a multi-select mode), this will result in the following SQL:
141
+
142
+ --- SQL
143
+ ( table.field IN ( '1', '2' ) OR table.field IS NULL )
144
+ ---
145
+
146
+ "See an online example":http://grid.leikind.org/null_values
147
+
148
+ h4. Wice::Defaults::STRING_MATCHING_OPERATORS
149
+
150
+ in addition to the configuration constant @Wice::Defaults::STRING_MATCHING_OPERATOR@ to define the operator for matching strings (@LIKE@ in most cases), hash @Wice::Defaults::STRING_MATCHING_OPERATORS@ was added to specify string matching operators on per-database basis:
151
+
152
+ --- Ruby
153
+ Wice::Defaults::STRING_MATCHING_OPERATORS = {
154
+ 'ActiveRecord::ConnectionAdapters::MysqlAdapter' => 'LIKE',
155
+ 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter' => 'ILIKE'
156
+ }
157
+ ---
158
+
159
+ A use-case for this is a Rails application connecting to two databases, one of which is MySQL, and the other is Postgresql. To use case-insensitive matching in Postgresql 'ILIKE' has to be used, but this operator is unknown to MySQL.
160
+
161
+ h4. td_html_attrs and table_html_attrs shortcuts
162
+
163
+ @:td_html_attrs@ in column definitions and @table_html_attrs@ in the table definitions are mostly used to add css classes, so a shorter way has been added to add css classes.
164
+
165
+ Instead of
166
+
167
+ --- RHTML
168
+ <%= grid(@grid, :table_html_attrs => {:class => 'css_class1'}) do |g|
169
+ g.column(:td_html_attrs => {:class => 'css_class2'}) do
170
+ ...
171
+ end
172
+ end -%>
173
+ ---
174
+
175
+ It's possible to just use the new @:class@ option:
176
+
177
+ --- RHTML
178
+ <%= grid(@grid, :class => 'css_class1') do |g|
179
+ g.column(:class => 'css_class2') do
180
+ end
181
+ end -%>
182
+ ---
183
+
184
+ h4. allow_multiple_selection
185
+
186
+ New options for @column@: @:allow_multiple_selection@, use @:allow_multiple_selection => false@ to disable switching between single and multiple selection modes for custom dropdown boxes.
187
+
188
+ "See an online example":http://grid.leikind.org/custom_filters4
189
+
190
+ h4. allow_ordering
191
+
192
+ New parameter for @column@: @:allow_ordering@. Use @:allow_ordering => false@ to disable the ordering of the column.
193
+
194
+ "See an online example":http://grid.leikind.org/basics6
195
+
196
+ h4. allow_showing_all_records
197
+
198
+ Parameter @:allow_showing_all_records@ moved from @initialize_grid@ to the view helper.
199
+
200
+ h4. other
201
+
202
+ * Default styles updated.
203
+ * Javascript code cleaned up and refactored.
204
+ * Quite some number of bugs fixed
205
+
206
+ == 0.4
207
+
208
+ * Detached filters: it has become possible to detach filters and place them anywhere on the page, before or after the grid.
209
+ Read section "Detached Filters" in the README.
210
+
211
+ * More control over Submit and Reset buttons.
212
+ Two new view helpers: submit_grid_javascript returns javascript which applies current filters; reset_grid_javascript returns javascript
213
+ which resets the grid, clearing the state of filters. This allows to create your own Submit and Reset buttons anywhere on the page
214
+ with the help of button_to_function:
215
+
216
+ <%= button_to_function "Submit", submit_grid_javascript(@grid) %>
217
+ <%= button_to_function "Reset", reset_grid_javascript(@grid) %>
218
+
219
+ To complement this feature there are two new parameters in the +grid+ helper :hide_submit_button and :hide_reset_button which
220
+ hide default buttons in the grid if set to true. Together with detached filter this allows to completely
221
+ get rid of the filter row with filters and icons.
222
+
223
+ * erb_mode option has been moved to the grid view helper - watch for warnings and remove the parameter from initialize_grid if you have it there.
224
+
225
+ * helper include_wice_grid_assets will require WiceGrid javascripts and stylesheets on demand, that is, only if at least one initialize_grid
226
+ has been called in the controller. Otherwise the helper returns an empty string. However, you can force the old unconditioned behavior if you
227
+ need by submitting parameter :load_on_demand set to false:
228
+ <%= include_wice_grid_assets(:load_on_demand => false) %>
229
+
230
+ * Compatibility with Rails asset caching. Helpers names_of_wice_grid_stylesheets and names_of_wice_grid_javascripts return names of stylesheet and
231
+ javascript files and can be used with stylesheet_link_tag and javascript_include_tag with :cache => true. Using this trick you have to deal with
232
+ the parameters correctly, mind that Prototype has to be loaded before WiceGrid javascripts:
233
+
234
+ <%= stylesheet_link_tag *(['core', 'modalbox'] + names_of_wice_grid_stylesheets + [ {:cache => true}]) %>
235
+ <%= javascript_include_tag *([:defaults] + names_of_wice_grid_javascripts + [ 'ui', 'swfobject', {:cache => true}]) %>
236
+
237
+ * When a page with a WiceGrid instance is loaded there is check a small chunk of javascript that checks whether Prototype is loaded and whether
238
+ the main WiceGrid javascript files is loaded and is of the correct version. Problems are reported to the user via alert() dialog boxes.
239
+ This check has now been disabled in the production mode.
240
+
241
+ * The default field separator in generated CSV (comma) can now be overridden by setting :enable_export_to_csv to a string instead of +true+.
242
+
243
+ * It is possible to add your own handcrafted HTML after and/or before each grid row. This works similar to +row_attributes+,
244
+ by adding blocks after_row and before_row:
245
+
246
+ <%= grid(@tasks_grid) do |g|
247
+ g.before_row do |task|
248
+ if task.active?
249
+ "<tr><td colspan=\"10\">Custom line for #{t.name}</td></tr>" # this would add a row
250
+ # before every active task row
251
+ else
252
+ nil
253
+ end
254
+ end
255
+ .......
256
+ end %>
257
+
258
+
259
+
260
+ * Bug fixes
261
+
262
+ * Refactoring
263
+ =============
264
+
265
+ === 03/04/2009
266
+
267
+ Possibility to add custom lines after and/or before a grid row.
268
+
269
+
270
+ === 16/03/2009
271
+
272
+ Option to override the default field separator in generated CSV (comma).
273
+
274
+
275
+ === 13/02/2009
276
+
277
+ a bug fix for incorrect generation if dom ids for javascript calendar filter. Happened only for columns belonging to joined tables
278
+
279
+ === 12/01/2009
280
+
281
+ WiceGrid 0.3 released
282
+
283
+ === 12/01/2009
284
+
285
+ All records mode
286
+
287
+ === 10/12/2008
288
+
289
+ custom_filter made Rails-compliant, a new flavor - Array of two-element arrays
290
+
291
+ === 4/12/2008
292
+ A single helper to include all assets in a page
293
+
294
+ A javascript error message if Prototype is not loaded
295
+
296
+ A javascript error message if wice_grid.js is not loaded
297
+
298
+ Added status info to the pagination line:
299
+ « Previous 1 2 3 Next » 1-20 / 50
300
+
301
+ === 3/12/2008
302
+ First implementation of saved queries
303
+
304
+
305
+ === 25/11/2008
306
+
307
+ Negation for string filters: match records where this fiels DOES NOT include the given fragment.
308
+
309
+ === 24/11/2008
310
+
311
+ The string matching operator for string filters (LIKE) has been moved to wice_grid_config.rb in order to make it easier to substitute it with
312
+ something else, for example, ILIKE of Postgresql.
313
+
314
+
315
+ === 19/11/2008
316
+
317
+ Experimental feature : :table_alias parameter to allow ordering and filtering for joining associations referring the same table.
318
+ (See "Joined associations referring to the same table" in README)
319
+
320
+ === 18/11/2008
321
+
322
+ Refactoring
323
+
324
+ === 6/11/2008
325
+
326
+ Ability to provide a callback to a Proc object or a method, the callback will be called with the objects of the current selection of
327
+ objects (throughout all pages). Can be used to use the WiceGrid filters set up by the user for further processing of the user's selection of
328
+ objects.
329
+
330
+ === 5/11/2008
331
+
332
+ Javascript calendars as Date/Datetime filters
333
+
334
+
335
+ === 4/11/2008
336
+
337
+ Ability to inject custom sql code into the ORDER BY clause, for example, ORDER BY char_length(table1.foo)
338
+
339
+ === 4/11/2008
340
+
341
+ Creates a new branch for version 2.3
342
+
343
+
344
+
345
+ === 21/10/2008
346
+
347
+ A bugfix related to custom filters influencing other columns with filters
348
+ A more informative error message if the grid can't find the underlying database column for a view column (incorrect :column_name and :model_class)
349
+
350
+ === 8/10/2008
351
+
352
+ New view helper parameter <tt>:sorting_dependant_row_cycling</tt> - When set to true (by default it is false) the row styles +odd+ and +even+
353
+ will be changed only when the content of the cell belonging to the sorted column changes. In other words, rows with identical values in the
354
+ ordered column will have the same style (color).
355
+
356
+ === 3/10/2008
357
+
358
+ For simple columns like
359
+
360
+ g.column :column_name => 'Username', :attribute_name => 'username' do |account|
361
+ account.username
362
+ end
363
+
364
+ the following blockless shortcut can be used:
365
+
366
+ g.column :column_name => 'Username', :attribute_name => 'username'
367
+
368
+ In this case +attribute_name+ will be used as the method name to send to the ActiveRecord instance.
369
+
370
+ === revision 27 (30/09/2008)
371
+
372
+ * CSV export
373
+ * Custom filters can switch between a dropdown list and a multiple select list, thus allowing to search for records matching
374
+ more that one value (operator OR)
375
+
376
+ === revision 17 (19/08/2008)
377
+
378
+ * A bug fixed: extra_request_parameters did not propagate to will_paginate page panel. Now it does.
379
+
380
+ === revision 13 (6/08/2008)
381
+
382
+ * File <tt>config.rb</tt> renamed.
383
+ * New parameters for +column+ :
384
+ * <tt>:boolean_filter_true_label</tt> - overrides the default value for <tt>BOOLEAN_FILTER_TRUE_LABEL</tt> ('+yes+') in the config.
385
+ Only has effect in a column with a boolean filter.
386
+ * <tt>:boolean_filter_false_label</tt> - overrides the default value for <tt>BOOLEAN_FILTER_FALSE_LABEL</tt> ('+no+') in the config.
387
+ Only has effect in a column with a boolean filter.
388
+ * <tt>:filter_all_label</tt> - overrides the default value for <tt>BOOLEAN_FILTER_FALSE_LABEL</tt> ('<tt>--</tt>') in the config.
389
+ Has effect in a column with a boolean filter _or_ a custom filter.
390
+
391
+ === revision 11
392
+
393
+ * New row_attributes method to dynamically generate HTML attributes for the <tt><tr></tt> tag:
394
+
395
+ <%= grid(@portal_applications_grid) do |g|
396
+ g.row_attributes{ |portal_application|
397
+ {:id => "#{@portal_applications_grid.name}_row_#{portal_application.id}"}
398
+ }
399
+
400
+ g.column{ |portal_application| ... }
401
+ g.column{ |portal_application| ... }
402
+ end -%>
403
+
404
+ * The column block can now optionally return an array of two values, where the first element is the cell
405
+ contents and the second is a hash of HTML attributes to be added for the <td> tag of the current cell.
406
+
407
+ === revision 10
408
+
409
+ * New parameter +grid+ parameter: <tt>:extra_request_parameters</tt>.
410
+ (Read http://redmine.wice.eu/api/wice_grid/classes/Wice/GridViewHelper.html#M000002)
411
+
412
+ === 0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Yuri Leikind & the WICE team (http://wice.eu)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,1179 @@
1
+ = WiceGrid
2
+
3
+ Version:: 3.0.0.pre1
4
+ Author:: Yuri Leikind
5
+ Homepage:: http://leikind.org/pages/wicegrid
6
+ Examples online:: http://grid.leikind.org
7
+ News:: http://leikind.org/wicegrid
8
+ Email:: "Yuri Leikind" <yuri.leikind at gmail dot com>
9
+
10
+ == Attention!
11
+ There are two major branches of WiceGrid.
12
+
13
+ THIS IS AN ALPHA VERSION OF THE PLUGIN FOR RAILS 3.0.
14
+ The current branch (https://github.com/leikind/wice_grid/tree/rails3) starts with version 3.0, works with Rails 3, and can only be used as a gem.
15
+
16
+ For Rails 2 WiceGrid only works as a Rails plugin. See WiceGrid version 0.6 (https://github.com/leikind/wice_grid/).
17
+
18
+ == Intro
19
+
20
+ WiceGrid is a Rails grid plugin.
21
+
22
+ One of the goals of this plugin was to allow the programmer to define the contents of the cell by himself, just like one does when rendering a collection via a simple table (and this is what differentiates WiceGrid from various scaffolding solutions), but automate implementation of filters, ordering, paginations, CSV export, and so on. Ruby blocks provide an elegant means for this.
23
+
24
+
25
+ WiceGrid builds the call to the ActiveRecord layer for you and creates a table view with the results of the call including:
26
+
27
+ * paging
28
+ * sortable columns
29
+ * filtering by multiple columns
30
+ * CSV export
31
+ * saving queries
32
+
33
+ All working nicely together. Filters are added automatically according to the type of the underlying DB column. Filtering by more than one column at the same time is possible. More than one such grid can appear on a page, and manipulations with one grid do not have any impact on the other.
34
+
35
+ WiceGrid does not take a collection as an input, it works directly with ActiveRecord (with the help of <tt>will_paginate[http://github.com/mislav/will_paginate/wikis]</tt>).
36
+
37
+ WiceGrid does not use AJAX calls to reload itself, instead simple GET requests are used for this, nevertheless, all other page parameters are respected and preserved. WiceGrid views do not contain forms so you can include it in your own forms.
38
+
39
+ There are two major branches of WiceGrid.
40
+
41
+ The current branch (https://github.com/leikind/wice_grid/tree/rails3) starts with version 3.0, works with Rails 3, and can only be used as a gem.
42
+
43
+ For Rails 2 WiceGrid only works as a Rails plugin. See WiceGrid version 0.6 (https://github.com/leikind/wice_grid/).
44
+
45
+ WiceGrid is known to work with MySQL and Postgres.
46
+
47
+ WiceGrid works with Prototype and jQuery
48
+
49
+ === Examples
50
+
51
+ This tutorial is accompanied by a sample application with WiceGrid examples which you can browse online ( http://grid.leikind.org ), or just view the code ( http://github.com/leikind/wice_grid_examples ).
52
+
53
+
54
+ == Requirements
55
+
56
+ Rails version 3.0 or newer.
57
+
58
+ <tt>will_paginate[http://github.com/mislav/will_paginate/wikis]</tt> version 3.0.pre2 or newer.
59
+
60
+ <tt>Prototype[http://www.prototypejs.org]</tt> version 1.5.1 or newer, or <tt>jQuery[http://jquery.com/]</tt>.
61
+
62
+ == How-To
63
+
64
+ === Installation
65
+
66
+ Install the gem:
67
+
68
+ gem install --pre wice_grid
69
+
70
+ If your application is Prototype-based , run the following generator to copy all plugin assets:
71
+
72
+ rails g wice_grid_assets_prototype
73
+
74
+ For jQuery:
75
+
76
+ rails g wice_grid_assets_jquery
77
+
78
+ This will copy images, stylesheets, configuration file <tt>config/initializers/wice_grid_config.rb</tt>, and the correct version of javascript files.
79
+
80
+ === Support for Prototype and jQuery
81
+
82
+ WiceGrid started as a plugin using the Prototype javascript framework. Support for jQuery was added for version 0.6.
83
+ The plugin contains two versions of the main javascript file <tt>wice_grid.js</tt>, and depending on the generator run to
84
+ install the assets (+wice_grid_assets_prototype+ or +wice_grid_assets_jquery+) the correct file is copied into <tt>public/javascripts</tt>.
85
+
86
+ Some javascript code is also generated and injected into the HTML page. The value of constant <tt>Wice::Defaults::JS_FRAMEWORK</tt> in
87
+ configuration file <tt>wice_grid_config.rb</tt> defines for which JS framework code should be generated.
88
+ Generators +wice_grid_assets_prototype+ and +wice_grid_assets_jquery+ create a version of <tt>wice_grid_config.rb</tt>
89
+ with the corresponding value of <tt>Wice::Defaults::JS_FRAMEWORK</tt>.
90
+
91
+
92
+ In the Prototype mode the plugin uses a forked[http://github.com/leikind/calendarview] version of Calendarview[http://github.com/jsmecham/calendarview]. It is bundled with the plugin and the generator task
93
+ +wice_grid_assets_prototype+ will install al necessary assets.
94
+
95
+ The jQuery version uses jQuery datepicker[http://jqueryui.com/demos/datepicker/]. Because this is part
96
+ of the standard jQuery codebase, it is not bundled together with the plugin, and it is the responsibility
97
+ of the programmer to include all necessary assets including localization files if the application is
98
+ multilingual.
99
+
100
+ It is always possible to fall back to simple dropdown lists that the standard date/datetime Rails helpers use.
101
+
102
+ JQUERY DATEPICKER IS ONLY USED FOR DATE FILTERS AT THE MOMENT. DATETIME FILTERS FALL BACK TO THE DEFAULT
103
+ RAILS DATE/DATETIME HELPERS.
104
+
105
+
106
+ === Basics
107
+
108
+ The Prototype version of WiceGrid requires <tt>prototype.js</tt> and <tt>effects.js</tt> in order to function.
109
+ The jQuery version of WiceGrid requires <tt>jquery.js</tt>, the Datepicker widget from jQuery UI, and the Highlight and Fade effects for the saved queries functionality.
110
+
111
+ Thus, make sure you require all necessary JS assets in your layout template.
112
+
113
+ To include WiceGrid javascript and stylesheet files to the page use helper +include_wice_grid_assets+ :
114
+
115
+ <%= include_wice_grid_assets %>
116
+
117
+ The default behavior of +include_wice_grid_assets+ is a bit magical in the sense that it
118
+ produces no output if the page contains no grids, so don't panic if you see no WiceGrid includes.
119
+ If you prefer to always have WiceGrid stylesheet and javascript, use
120
+
121
+ <%= include_wice_grid_assets :load_on_demand => false %>
122
+
123
+ The simplest example of a WiceGrid for one simple DB table called ApplicationAccount is the following:
124
+
125
+ Controller:
126
+
127
+ @tasks_grid = initialize_grid(Task)
128
+
129
+ View:
130
+
131
+ <%= grid(@tasks_grid) do |g|
132
+
133
+ g.column do |task|
134
+ task.id
135
+ end
136
+
137
+ g.column do |task|
138
+ task.title
139
+ end
140
+
141
+ g.column do |task|
142
+ task.description
143
+ end
144
+
145
+ g.column do |task|
146
+ task.archived? ? 'Yes' : 'No'
147
+ end
148
+
149
+ g.column do |task|
150
+ link_to('Edit', edit_task_path(task))
151
+ end
152
+ end -%>
153
+
154
+ Code <tt>g.column do |task| ... end</tt>
155
+ defines everything related to a column in the resulting view table including column names, sorting, filtering, the content of the column cells, etc.
156
+ The return value of the block is the table cell content.
157
+
158
+ In the above view code five columns were defined, all without names, no sorting or filtering is available. Still, pagination becomes active if
159
+ the number of all extracted records exceeds the default number of rows per page.
160
+
161
+ Column names are defined with parameter <tt>:column_name</tt>:
162
+
163
+ <%= grid(@tasks_grid) do |g|
164
+
165
+ g.column :column_name => 'ID' do |task|
166
+ task.id
167
+ end
168
+
169
+ g.column :column_name => 'Title' do |task|
170
+ task.title
171
+ end
172
+
173
+ g.column :column_name => 'Description' do |task|
174
+ task.description
175
+ end
176
+
177
+ g.column :column_name => 'Archived' do |task|
178
+ task.archived? ? 'Yes' : 'No'
179
+ end
180
+
181
+ g.column do |task|
182
+ link_to('Edit', edit_task_path(task))
183
+ end
184
+ end -%>
185
+
186
+ To add filtering and ordering, declare to which column in the underlying database table(s) the view column corresponds using
187
+ parameter <tt>:attribute_name</tt> :
188
+
189
+ <%= grid(@tasks_grid) do |g|
190
+
191
+ g.column :column_name => 'ID', :attribute_name => 'id' do |task|
192
+ task.id
193
+ end
194
+
195
+ g.column :column_name => 'Title', :attribute_name => 'title' do |task|
196
+ task.title
197
+ end
198
+
199
+ g.column :column_name => 'Description', :attribute_name => 'description' do |task|
200
+ task.description
201
+ end
202
+
203
+ g.column :column_name => 'Archived', :attribute_name => 'archived' do |task|
204
+ task.archived? ? 'Yes' : 'No'
205
+ end
206
+
207
+ g.column do |task|
208
+ link_to('Edit', edit_task_path(task))
209
+ end
210
+ end -%>
211
+
212
+ This will add sorting links and filters for columns +Username+ and +Active+.
213
+ The plugin automatically creates filters according to the type
214
+ of the database column. In the above example a text field will be created for column Title (title is a string),
215
+ for column +Archived+ a dropdown filter will be created with options 'Yes', 'No', and '--', and for the integer ID two short text fields are
216
+ added which can contain the numeric range (more than, less than).
217
+
218
+ It is important to remember that <tt>:attribute_name</tt> is the name of the database column, not a model attribute. Of course, all database columns have corresponding model attributes, but not all model attributes map to columns in the same table with the same name.
219
+
220
+ Read more about available filters in the documentation
221
+ for the column method. Read the section about custom dropdown filters for more advanced filters.
222
+
223
+
224
+ For columns like
225
+
226
+ g.column :column_name => 'Title', :attribute_name => 'title' do |task|
227
+ task.title
228
+ end
229
+
230
+ where the block contains just a call to the same attribute declared by :attribute_name, the block can be omitted:
231
+
232
+ <%= grid(@tasks_grid) do |g|
233
+
234
+ g.column :column_name => 'ID', :attribute_name => 'id'
235
+
236
+ g.column :column_name => 'Title', :attribute_name => 'title'
237
+
238
+ g.column :column_name => 'Description', :attribute_name => 'description'
239
+
240
+ g.column :column_name => 'Archived', :attribute_name => 'archived' do |task|
241
+ task.archived? ? 'Yes' : 'No'
242
+ end
243
+
244
+ g.column do |task|
245
+ link_to('Edit', edit_task_path(task))
246
+ end
247
+ end -%>
248
+
249
+
250
+ In this case +attribute_name+ will be used as the method name to send to the ActiveRecord instance.
251
+
252
+ If only sorting is needed, we can turn off filters using <tt>:no_filter</tt> :
253
+
254
+ g.column :column_name => 'ID', :attribute_name => 'id', :no_filter => true
255
+
256
+ If no ordering links are needed, use <tt>:allow_ordering</tt>:
257
+
258
+ g.column :column_name => 'Added', :attribute_name => 'created_at', :allow_ordering => false
259
+
260
+ It is important to understand that it is up to the developer to make sure that the value returned by a column block (the content of a cell) corresponds to the underlying database column specified by <tt>:attribute_name</tt> (and <tt>:model_class</tt> discussed below).
261
+
262
+
263
+ === Rendering filter panel
264
+
265
+ The filter panel can be shown and hidden clicking the icon with binoculars.
266
+
267
+ The way the filter panel is shown after the page is loaded is controlled via parameter <tt>:show_filters</tt> of the <tt>grid</tt> helper.
268
+ Possible values are:
269
+
270
+ * <tt>:when_filtered</tt> - the filter is shown when the current table is the result of filtering
271
+ * <tt>:always</tt> - show the filter always
272
+ * <tt>:no</tt> - never show the filter
273
+
274
+ Example:
275
+
276
+ <%= grid(@tasks_grid, :show_filters => :always) do |g|
277
+ ......
278
+ end -%>
279
+
280
+
281
+ Filter related icons (filter icon, reset icon, show/hide icon) are placed in the header of the last column if
282
+ it doesn't have any filter or a column name, otherwise an additional table column is added. To always place
283
+ the icons in the additional column, set <tt>Wice::Defaults::REUSE_LAST_COLUMN_FOR_FILTER_ICONS</tt> to +false+ in
284
+ the configuration file.
285
+
286
+
287
+ === Initial Ordering
288
+
289
+ Initializing the grid we can also define the column by which the record will be ordered <em>on the first rendering of the grid</em>, when the user has not set their ordering setting by clicking the column label, and the order direction:
290
+
291
+ @tasks_grid = initialize_grid(Task,
292
+ :order => 'tasks.title',
293
+ :order_direction => 'desc'
294
+ )
295
+
296
+ === Records Per Page
297
+
298
+ The number of rows per page is set with <tt>:per_page</tt>:
299
+
300
+ @tasks_grid = initialize_grid(Task, :per_page => 40)
301
+
302
+ === Conditions
303
+
304
+ The +initialize_grid+ method supports a <tt>:conditions</tt> parameter which is passed on to the underlying ActiveRecord (via will_paginate), so it can be in any format processable by ActiveRecord:
305
+
306
+ @tasks_grid = initialize_grid(Task,
307
+ :conditions => ["archived = false and estimated_time > ?", 100]
308
+ )
309
+
310
+ @tasks_grid = initialize_grid(Task,
311
+ :include => :project,
312
+ :conditions => {:archived => false, :project => {:active => true}}
313
+ )
314
+
315
+
316
+
317
+ A good example is substituting a common pattern like
318
+
319
+ @user_groups = @portal_application.user_groups
320
+
321
+ with WiceGrid code:
322
+
323
+ @user_groups_grid = initialize_grid(UserGroup, :conditions => ['portal_application_id = ?', @portal_application])
324
+
325
+
326
+ === Queries with join tables
327
+
328
+ WiceGrid also supports ActiveRecord's <tt>:joins</tt> and <tt>:include</tt>.
329
+
330
+ @products_grid = initialize_grid(Product,
331
+ :include => :category,
332
+ :order => 'products.name',
333
+ :per_page => 20)
334
+
335
+ Note that if we want to order initially by a column from a joined table we have to specify the table and the column name with the sql dot notation, that is, <tt>products.name</tt>
336
+
337
+ To show columns of joined tables in the view table, the ActiveRecord model class name has to be specified, that corresponds to the joined table:
338
+
339
+ <%= grid(@products_grid) do |g|
340
+ g.column :column_name => 'Product Name', :attribute_name => 'name' do |product| # primary table
341
+ link_to(product.name, product_path(product))
342
+ end
343
+
344
+ g.column :column_name => 'Category', :attribute_name => 'name', :model_class => Category |product| # joined table
345
+ product.category.name
346
+ end
347
+ %>
348
+
349
+ Please note that the blockless definition of the column only works with columns from the main table and it won't work with columns with <tt>:model_class</tt>
350
+
351
+ === Joined associations referring to the same table
352
+
353
+ In case there are two joined associations both referring to the same table, ActiveRecord constructs a query where
354
+ the second join provides an alias for the joined table. To enable WiceGrid to order and filter by columns belonging to different associations
355
+ but originating from the same table, set <tt>:table_alias</tt> to this alias:
356
+
357
+ Model:
358
+
359
+ class Project < ActiveRecord::Base
360
+ belongs_to :customer, :class_name => 'Company'
361
+ belongs_to :supplier, :class_name => 'Company'
362
+ end
363
+
364
+ Controller:
365
+
366
+ @projects_grid = initialize_grid(Project, :include => [:customer, :supplier] )
367
+
368
+
369
+ View:
370
+
371
+ <%= grid(@projects_grid, :show_filters => :always) do |g|
372
+
373
+ g.column :column_name => 'Project Name', :attribute_name => 'name'
374
+
375
+ g.column :column_name => 'Customer company', :model_class => 'Company', :attribute_name => 'name' do |task|
376
+ task.customer.name if task.customer
377
+ end
378
+
379
+ g.column :column_name => 'Supplier company', :model_class => 'Company', :attribute_name => 'name', :table_alias => ' suppliers_projects' do |task|
380
+ task.supplier.name if task.supplier
381
+ end
382
+
383
+ end -%>
384
+
385
+
386
+ === More than one grid on a page
387
+
388
+ It is possible to use more that one grid on a page, each with its own state. To do so, you must specify the name of the grid in +initialize_grid+ using
389
+ parameter <tt>:name</tt>
390
+
391
+ The name serves as the base name for HTTP parameters, DOM IDs, etc, so it is important that all grids on a page have different names. The default
392
+ name is 'grid'.
393
+
394
+ The name can only contain alphanumeric characters.
395
+
396
+ @projects_grid = initialize_grid(Project, :name => 'g1' )
397
+ @tasks_grid = initialize_grid(Task, :name => 'g2')
398
+
399
+
400
+ === Custom Ordering
401
+
402
+ It is possible to change the way results are ordered injecting a piece of SQL code, for example, use
403
+ <tt>ORDER BY INET_ATON(ip_address)</tt> instead of <tt>ORDER BY ip_address</tt>.
404
+
405
+ To do so, provide parameter <tt>:custom_order</tt> in the initialization of the grid with a hash where keys are fully qualified names
406
+ of database columns, and values the required chunks of SQL to use in the ORDER BY clause.
407
+
408
+ For example:
409
+
410
+
411
+ @hosts_grid = initialize_grid(Host,
412
+ :custom_order => {
413
+ 'hosts.ip_address' => 'INET_ATON(hosts.ip_address)'
414
+ })
415
+
416
+
417
+ It is possible to use the '?' character instead of the name of the column in the hash value:
418
+
419
+ @hosts_grid = initialize_grid(Host,
420
+ :custom_order => {
421
+ 'hosts.ip_address' => 'INET_ATON( ? )'
422
+ })
423
+
424
+ Values can also be Proc objects. The parameter supplied to such a Proc object is the name of the column:
425
+
426
+ @hosts_grid = initialize_grid(Host,
427
+ :custom_order => {
428
+ 'hosts.ip_address' => lambda{|f| "INET_ATON( #{f} )"}
429
+ })
430
+
431
+
432
+ === Custom dropdown filters
433
+
434
+ It is possible to construct custom dropdown filters. Depending on the value of <tt>column</tt> parameter<tt>:custom_filter</tt> different
435
+ modes are available:
436
+
437
+
438
+ ==== Array of two-element arrays or a hash
439
+
440
+ An array of two-element arrays or a hash are semantically identical ways of creating a custom filter.
441
+
442
+ Every first item of the two-element array is used for the label of the select option while the second element is the value of the select option. In case of a hash the keys become the labels of the generated dropdown list, while the values will be values of options of the dropdown list:
443
+
444
+ g.column :column_name => 'Status', :attribute_name => 'status',
445
+ :custom_filter => {'Development' => 'development', 'Testing' => 'testing', 'Production' => 'production'}
446
+
447
+ g.column :column_name => 'Status', :attribute_name => 'status',
448
+ :custom_filter => [['Development', 'development'], ['Testing', 'testing'], ['Production', 'production']]
449
+
450
+ It is also possible to submit a array of strings or numbers, in this case every item will be used both as the value of the select option and as its label:
451
+
452
+ g.column :column_name => 'Status', :attribute_name => 'status',
453
+ :custom_filter => ['development', 'testing', 'production']
454
+
455
+
456
+ ==== :auto
457
+
458
+ <tt>:auto</tt> - a powerful option which populates the dropdown list with all unique values of the column specified by
459
+ <tt>:attribute_name</tt> and <tt>:model_class</tt>.
460
+
461
+ g.column :column_name => 'Status', :attribute_name => 'status',
462
+ :custom_filter => ['development', 'testing', 'production']
463
+
464
+ Note that in the above example all names of all possible categories will appear even if they don't appear in the current resultset.
465
+ To only show those which do appear in the resutset, use an array of symbol messages (see section 'An array of symbols').
466
+
467
+
468
+ ==== Custom filters and associations (joined tables)
469
+
470
+ In most cases custom fields are required for one-to-many and many-to-many associations.
471
+
472
+ To correctly build a filter condition foreign keys have to be matched.
473
+
474
+ For example, if there is a column:
475
+
476
+ g.column :column_name => 'Project Name', :attribute_name => 'name', :model_class => 'Project' do |task|
477
+ task.project.name if task.project
478
+ end
479
+
480
+ adding <tt>:custom_filter</tt> like this:
481
+
482
+ g.column :column_name => 'Project Name', :attribute_name => 'name', :model_class => 'Project',
483
+ :custom_filter => Project.find(:all).map{|pr| [pr.name, pr.name]} do |task|
484
+ task.project.name if task.project
485
+ end
486
+
487
+ is bad style and can fail, because the resulting condition will compare the name of the project, <tt>projects.name</tt> to a string,
488
+ and in some databases it is possible that different records (projects in our example) have the same name.
489
+
490
+ To use filter with foreign keys, we have to change the declaration of the column from <tt>projects.name</tt>, to
491
+ <tt>tasks.project_id</tt>, and build the dropdown with foreign keys as values:
492
+
493
+
494
+ g.column :column_name => 'Project Name', :attribute_name => 'tasks.project_id',
495
+ :custom_filter => Project.find(:all).map{|pr| [pr.id, pr.name]} do |task|
496
+ task.project.name if task.project
497
+ end
498
+
499
+ However, this will break the ordering of the column - the column will be ordered by the integer foreign key. To fix this,
500
+ we can override the ordering using <tt>:custom_order</tt>:
501
+
502
+ @tasks_grid = initialize_grid(Task,
503
+ :include => :project,
504
+ :custom_order => {
505
+ 'tasks.project_id' => 'projects.name'
506
+ }
507
+ )
508
+
509
+
510
+ ==== Any other symbol (method name) or an array of symbols (method names)
511
+
512
+
513
+ For one symbol (different from <tt>:auto</tt>) the dropdown list is populated by all unique values returned by the method with this name
514
+ sent to <em>all</em> ActiveRecord objects throughout all pages.
515
+
516
+ The conditions set up by the user are ignored, that is, the records used are all those found on all pages without any filters active.
517
+
518
+ For an array of symbols, the first method name is sent to the ActiveRecord
519
+ object if it responds to this method, the second method name is sent to the
520
+ returned value unless it is +nil+, and so on. In other words, a single symbol mode is the
521
+ same as an array of symbols where the array contains just one element.
522
+
523
+ g.column :column_name => 'Version', :attribute_name => 'expected_version_id', :custom_filter => [:expected_version, :to_option] do |task|
524
+ task.expected_version.name if task.expected_version
525
+ end
526
+
527
+
528
+ There are two important differences from <tt>:auto</tt>:
529
+
530
+ 1. The method does not have to be a field in the result set, it is just some value computed in the method after the database call and ActiveRecord instantiation.
531
+ 2. Filtering by any option of such a custom filter will bring a non-empty list, unlike with <tt>:auto</tt>.
532
+
533
+
534
+ This mode has one major drawback - this mode requires an additional query without +offset+ and +limit+ clauses to instantiate _all_
535
+ ActiveRecord objects, and performance-wise it brings all the advantages of pagination to nothing. Thus, memory- and performance-wise this can be really bad for some queries and tables and should be used with care.
536
+
537
+
538
+ If the final method returns a atomic value like a string or an integer, it is used for both the value and the label of the select option element:
539
+
540
+ <option value="returned value">returned value</option>
541
+
542
+ However, if the retuned value is a two element array, the first element is used for the option label and the second - for the value.
543
+
544
+ Typically, a model method like the following:
545
+
546
+ def to_option
547
+ [name, id]
548
+ end
549
+
550
+ together with
551
+
552
+ :custom_filter => :to_option
553
+
554
+ would do the trick:
555
+
556
+ <option value="id">name</option>
557
+
558
+ Alternatively, a hash with the single key-value pair can be used, where the key will be used for the label, and the key - for the value:
559
+
560
+ def to_option
561
+ {name => id}
562
+ end
563
+
564
+
565
+ ==== Special treatment of values 'null' and 'not null'
566
+
567
+ Values 'null' and 'not null' in a generated custom filter are treated specially, as SQL +null+ statement and not as strings.
568
+ Value 'null' is transformed into SQL condition <tt>IS NULL</tt>, and 'not null' into <tt>IS NOT NULL</tt>
569
+
570
+ Thus, if in a filter defined by
571
+ :custom_filter => {'No' => 'null', 'Yes' => 'not null', '1' => 1, '2' => '2', '3' => '3'}
572
+ values '1', '2' and 'No' are selected (in a multi-select mode), this will result in the following SQL:
573
+
574
+ ( table.field IN ( '1', '2' ) OR table.field IS NULL )
575
+
576
+
577
+ ==== Multiple selection
578
+
579
+ By default it is possible for any dropdown list to switch between single and multiple selection modes. To only allow
580
+ single selection use <tt>:allow_multiple_selection</tt>:
581
+
582
+
583
+ g.column :column_name => 'Expected in version', :attribute_name => 'expected_version_id',
584
+ :custom_filter => [:expected_version, :to_option], :allow_multiple_selection => false do |task|
585
+ ...
586
+ end
587
+
588
+
589
+ === Defaults
590
+
591
+ Default values like can be changed in <tt>config/initializers/wice_grid_config.rb</tt>, as well grid labels and paths to some images.
592
+
593
+
594
+
595
+ === Submit/Reset buttons
596
+ View helper +submit_grid_javascript+ returns javascript which applies current filters.
597
+ View helper +reset_grid_javascript+ returns javascript which resets the grid, clearing the state of filters.
598
+ This allows to create your own Submit and Reset buttons anywhere on the page with the help of +button_to_function+:
599
+
600
+ <%= button_to_function "Submit", submit_grid_javascript(@grid) %>
601
+ <%= button_to_function "Reset", reset_grid_javascript(@grid) %>
602
+
603
+ To complement this feature there are two parameters in the +grid+ helper <tt>:hide_submit_button</tt> and <tt>:hide_reset_button</tt> which
604
+ hide default buttons in the grid if set to true.
605
+
606
+
607
+ === Auto-reloading filters
608
+
609
+ It is possible to configure a grid to reload itself once a filter has been changed. It works with all
610
+ filter types including the JS calendar, the only exception is the standard Rails date/datetime filters.
611
+
612
+ Use option <tt>:auto_reload</tt> in the column definiton:
613
+
614
+
615
+ <%= grid(@tasks_grid, :show_filters => :always, :hide_submit_button => true) do |g|
616
+
617
+ # String
618
+ g.column :column_name => 'Title', :attribute_name => 'title', :auto_reload => true
619
+
620
+ # Boolean
621
+ g.column :column_name => 'Archived', :attribute_name => 'archived', :auto_reload => true
622
+
623
+ # Custom (dropdown)
624
+ g.column :column_name => 'Status', :attribute_name => 'status_id', :custom_filter => Status.to_dropdown, :auto_reload => true do |task|
625
+ task.status.name if task.status
626
+ end
627
+
628
+ # Datetime
629
+ g.column :column_name => 'Added', :attribute_name => 'created_at', :auto_reload => true, :helper_style => :calendar do |task|
630
+ task.created_at.to_s(:short)
631
+ end
632
+
633
+ end -%>
634
+
635
+ To make this behavior default change constant +AUTO_RELOAD+ in the configuration file.
636
+
637
+ === Styling the grid
638
+
639
+ ==== Predefined css classes used by the grid
640
+
641
+ +td+ tags are assigned two styles automatically - +sorted+ if the column is the one by which the grid is ordered,
642
+ and +active_filter+ if the column's filter is on.
643
+
644
+ Odd and even +tr+ tags are assigned styles +odd+ and +even+, correspondingly.
645
+
646
+ For other classes see <tt>wice_grid.css</tt>. Feel free to customize it according to your needs.
647
+
648
+ ==== Adding classes and styles
649
+
650
+ The +grid+ helper accepts parameter <tt>:table_html_attrs</tt> which is a hash of HTML
651
+ attributes for the table tag.
652
+
653
+ Another +grid+ parameter is <tt>header_tr_html_attrs</tt> which is a hash of HTML attributes to be added to the first +tr+ tag (or two first +tr+'s if the filter row is present).
654
+
655
+ <tt>:td_html_attrs</tt> is a parameter for the +column+ method setting HTML attributes of +td+ tags for a certain column.
656
+
657
+ ==== Adding classes and styles dynamically
658
+
659
+ WiceGrid offers ways to dynamically add classes and styles to +TR+ and +TD+ based on the current ActiveRecord instance.
660
+
661
+
662
+ For <tt><TD></tt>, let the +column+ return an array where the first item is the usual
663
+ string output whole the second is a hash of HTML attributes to be added for the <tt><td></tt> tag of the current cell:
664
+
665
+ g.column do |portal_application|
666
+ css_class = portal_application.public? ? 'public' : 'private'
667
+ [portal_application.name, {:class => css_class}]
668
+ end
669
+
670
+ For adding classes/styles to <tt><TR></tt> use special clause +row_attributes+ , similar to +column+, only returning a hash:
671
+
672
+ <%= grid(@versions_grid) do |g|
673
+ g.row_attributes do |version|
674
+ if version.in_production?
675
+ {:style => 'background-color: rgb(255, 255, 204);'}
676
+ end
677
+ end
678
+
679
+ g.column{|version| ... }
680
+ g.column{|version| ... }
681
+ end -%>
682
+
683
+ Naturally, there can be only one +row_attributes+ definition for a WiceGrid instance.
684
+
685
+ Various classes do not overwrite each other, instead, they are concatenated.
686
+
687
+ WiceGrid icons are in directory <tt>public/images/icons/grid/</tt>.
688
+
689
+
690
+ === Adding rows to the grid
691
+
692
+ It is possible to add your own handcrafted HTML after and/or before each grid row. This works similar to +row_attributes+, by adding blocks +after_row+ and +before_row+:
693
+
694
+ <%= grid(@tasks_grid) do |g|
695
+ g.before_row do |task|
696
+ if task.active?
697
+ "<tr><td colspan=\"10\">Custom line for #{t.name}</td></tr>" # this would add a row
698
+ # before every active task row
699
+ else
700
+ nil
701
+ end
702
+ end
703
+ .......
704
+ end %>
705
+
706
+ It is up for the developer to return the correct HTML code, or return +nil+ if no row is needed for this record. Naturally, there is only one +before_row+ definition and one +after_row+ definition for a WiceGrid instance.
707
+
708
+ A real life example might be some enterprisy tables inside a table.
709
+
710
+ === Rendering a grid without records
711
+
712
+ If the grid does not contain any records to show, it is possible show some alternative view instead of an empty grid. Bear in mind that if the user
713
+ sets up the filters in such a way that the selection of records is empty, this will still render the grid and it will be possible to
714
+ reset the grid clicking on the Reset button. Thus, this only works if the initial number of records is 0.
715
+
716
+ <%= grid(@grid) do |g|
717
+
718
+ g.blank_slate do
719
+ "There are no records"
720
+ end
721
+
722
+ g.column do |product|
723
+ ...
724
+ end
725
+ end -%>
726
+
727
+ There are two alternative ways to do the same, submitting a string to +blank_slate+:
728
+
729
+ g.blank_slate "some text to be rendered"
730
+
731
+ Or a partial:
732
+
733
+ g.blank_slate :partial => "partial_name"
734
+
735
+
736
+ === Localization
737
+
738
+ Versions of WiceGrid newer than version 0.5 support localization via Rails I18n, however, without breaking
739
+ compatibility with pre-I18n versions of Rails (2.1.0 and older).
740
+
741
+ Running
742
+
743
+ ./script/generate wice_grid_assets
744
+
745
+ will copy file <tt>wice_grid.yml</tt> to <tt>config/locales</tt>.
746
+
747
+ The current locale is taken from <tt>I18n.locale</tt>. The locale also propagates to the javascript calendar
748
+ widget (see <tt>Calendar.messagebundle</tt> in <tt>calendarview.js</tt> to add languages).
749
+
750
+ If the messages are not found, or I18n is missing, WiceGrid will fall back to the hardcoded messages in
751
+ <tt>config/initializers/wice_grid_config.rb</tt>.
752
+
753
+ Currently supported languages are English, Dutch, French, and Russian.
754
+
755
+ === ERB mode
756
+
757
+ The view helper can function in two different modes. These are defined by its +erb_mode+ parameter.
758
+ By default (<tt>:erb_mode => false</tt>) the view helper is a simple helper surrounded by <tt><%=</tt> and <tt>%></tt>, like in all examples
759
+ above.
760
+
761
+
762
+ The second mode (<tt>:erb_mode => true</tt>) is called <em>ERB mode</em> and it allows to embed any ERB content inside blocks,
763
+ which is basically the style of the
764
+ <tt>form_for</tt> helper, only <tt>form_for</tt> takes one block, while inside the <tt>grid</tt> block there are other method calls taking
765
+ blocks as parameters:
766
+
767
+ <% grid(@countries_grid, :erb_mode => true) do |g| %>
768
+
769
+ <% g.column :column_name => 'Name', :attribute_name => 'name' do |country| %>
770
+ <b>Name: <%= link_to(country.name, country_path(country)) %></b>
771
+ <% end %>
772
+
773
+ <% g.column :column_name => 'Numeric Code', :attribute_name => 'numeric_code' do |country| %>
774
+ <i>Numeric Code: <%= country.numeric_code %></i>
775
+ <% end %>
776
+
777
+ <% end -%>
778
+
779
+ This mode can be usable if you like to have much HTML code inside cells.
780
+
781
+ Please remember that in this mode the helper opens with <tt><%</tt> instead of <tt><%=</tt>, similar to <tt>form_for</tt>.
782
+
783
+ The default value for <tt>:show_filters</tt> can be changed in <tt>config/initializers/wice_grid_config.rb</tt>.
784
+
785
+ === Action Column
786
+
787
+ It is easy to add a column with checkboxes for each record. This is useful for actions with multiple records,
788
+ for example, deleting selected records. Please note that +action_column+ only creates the checkboxes and the
789
+ 'Select All' and 'Deselect All' buttons, and the form itself as well as processing the parameters should be
790
+ taken care of by the application code.
791
+
792
+ <%= grid(@tasks_grid, :show_filters => :always) do |g|
793
+
794
+ ...
795
+
796
+ g.action_column
797
+
798
+ ...
799
+
800
+ end -%>
801
+
802
+ By default the name of the HTTP parameter follows pattern <tt>"#{grid_name}[#{param_name}][]"</tt>, thus
803
+ <tt>params[grid_name][param_name]</tt> will contain an array of object IDs.
804
+
805
+ See the documentation for more details.
806
+
807
+
808
+ === Integration of the grid with other forms on page
809
+
810
+ Imagine that the user should be able to change the behavior of the grid using some other control on the page, and not a grid filter.
811
+
812
+ For example, on a page showing tasks,
813
+ change between 'Show active tasks' to 'Show archived tasks' using a dropdown box.
814
+ WiceGrid allows to keep the status of the grid with all the filtering and sorting
815
+ using helper +dump_filter_parameters_as_hidden_fields+ which takes a grid object and dumps all current sorting and filtering parameters as
816
+ hidden fields. Just include <tt>dump_filter_parameters_as_hidden_fields(@grid)</tt> inside your form, and the newly rendered grid will
817
+ keep ordering and filtering.
818
+
819
+ <% form_tag('', :method => :get) do %>
820
+ <%= dump_filter_parameters_as_hidden_fields(@tasks_grid) %>
821
+ <%= select_tag 'archived',
822
+ options_for_select([['View active tasks', 0], ['View archived tasks', 1]], @archived ? 1 : 0),
823
+ :onchange => 'this.form.submit()' %>
824
+ <% end -%>
825
+
826
+
827
+ === Javascript Calendar for Date and DateTime Filters.
828
+
829
+ Standard Rails Date and DateTime helpers are a set of dropdown lists, and while this is practical,
830
+ displaying two Date or especially DateTime
831
+ helpers takes too much space on a page and is in general confusing.
832
+
833
+ To solve this, WiceGrid includes a second variant of Date/DateTime filters based on a Javascript calendar.
834
+
835
+ In the Prototype mode the plugin uses a forked[http://github.com/leikind/calendarview] version of Calendarview[http://github.com/jsmecham/calendarview]. It is bundled with the plugin and the generator task
836
+ +wice_grid_assets_prototype+ will install al necessary assets.
837
+
838
+ The jQuery version uses jQuery datepicker[http://jqueryui.com/demos/datepicker/]. Because this is part
839
+ of the standard jQuery codebase, it is not bundled together with the plugin, and it is the responsibility
840
+ of the programmer to include all necessary assets including localization files if the application is
841
+ multilingual.
842
+
843
+ It is always possible to fall back to simple dropdown lists that the standard date/datetime Rails helpers use.
844
+
845
+ JQUERY DATEPICKER IS ONLY USED FOR DATE FILTERS AT THE MOMENT. DATETIME FILTERS FALL BACK TO THE DEFAULT
846
+ RAILS DATE/DATETIME HELPERS.
847
+
848
+
849
+ Calendar based helpers are enabled by default, but it's possible to change it in
850
+ <tt>config/initializers/wice_grid_config.rb</tt>, variable HELPER_STYLE.
851
+
852
+ The flavor of the date filter can also be changed on per-column basis:
853
+
854
+ g.column :column_name => 'Due Date', :attribute_name => 'due_date', :helper_style => :calendar do |task|
855
+ task.due_date.to_s(:short) if task.due_date
856
+ end
857
+
858
+ g.column :column_name => 'Updated', :attribute_name => 'updated_at', :helper_style => :standard do |task|
859
+ task.created_at.to_s(:short)
860
+ end
861
+
862
+ Constants +DATE_FORMAT+ and +DATETIME_FORMAT+ define the format of dates the user will see, as well as the
863
+ format of the string sent in a HTTP parameter.
864
+
865
+ You can change the constants in
866
+ <tt>config/initializers/wice_grid_config.rb</tt>. Doing so, make sure that lamdbas defined
867
+ in +DATETIME_PARSER+ and +DATE_PARSER+ return valid DateTime and Date objects. The format
868
+ by default is <tt>%Y-%m-%d</tt> for the Date and the date part of DateTime, and <tt>Time.zone.parse</tt>
869
+ and <tt>Date.parse</tt> handle it.
870
+ Make sure it stays so.
871
+
872
+ jQuery +datepicker+ uses a different format flavor, therefore there is an additional constant
873
+ +DATE_FORMAT_JQUERY+. While +DATE_FORMAT_JQUERY+ is fed to +datepicker+, +DATE_FORMAT+ is still used
874
+ for presenting initial date values in filters, so make sure that +DATE_FORMAT_JQUERY+ and +DATE_FORMAT+
875
+ result in an identical date representation.
876
+
877
+
878
+ === Show All Records
879
+
880
+ It is possible to switch to the All Records mode clicking on link "show all" in the bottom right corner. This functionality should be used
881
+ with care. To turn this mode off for all grid instances, change constant +ALLOW_SHOWING_ALL_QUERIES+ in
882
+ <tt>config/initializers/wice_grid_config.rb</tt> to
883
+ +false+. To do so for a specific grid, use initializer parameter <tt>:allow_showing_all_records</tt>.
884
+
885
+ Configuration constant +START_SHOWING_WARNING_FROM+ sets the threshold number of all records after which clicking on the
886
+ link results in a javascript confirmation dialog.
887
+
888
+
889
+ === CSV Export
890
+
891
+ It is possible to export the data displayed on a grid to a CSV file. The dumped data is the current resultset with all the
892
+ current filters and sorting applied, only without the pagination constraint (i.e. all pages).
893
+
894
+ To enable CSV export add parameters +enable_export_to_csv+ and +csv_file_name+ to the initialization of the grid:
895
+
896
+ @projects_grid = initialize_grid(Project,
897
+ :include => [:customer, :supplier],
898
+ :name => 'g2',
899
+ :enable_export_to_csv => true,
900
+ :csv_file_name => 'projects'
901
+ )
902
+
903
+ +csv_file_name+ is the name of the downloaded file. This parameter is optional, if it is missing, the name of the grid is used instead.
904
+ The export icon will appear at the bottom right corner of the grid.
905
+
906
+ Next, each grid view helper should be placed in a partial of its own, requiring it from the master template for the usual flow. There must be no
907
+ HTML or ERB code in this partial except for the grid helper.
908
+
909
+ By convention the name of such a partial follows the following pattern:
910
+
911
+ _GRID_NAME_grid.html.erb
912
+
913
+ In other words, a grid named +tasks+ is expected to be found in a template called <tt>_tasks_grid.html.erb</tt> (remember that the default name of grids is '+grid+'.)
914
+
915
+ Next, method +export_grid_if_requested+ should be added to the end of each action containing grids with enabled CSV export.
916
+
917
+ +export_grid_if_requested+ intercepts CSV export requests and evaluates the partial with the required grid helper.
918
+
919
+ The naming convention for grid partials can be easily overridden by supplying a hash parameter to +export_grid_if_requested+
920
+ where each key is the name of a grid, and the value is the name of the template (like it is specified for +render+, i.e.
921
+ without '_' and extensions):
922
+
923
+
924
+ export_grid_if_requested('g1' => 'tasks_grid', 'g2' => 'projects_grid')
925
+
926
+ If the request is not a CSV export request, +export_grid_if_requested+ does nothing and returns +false+, if it is a CSV export request,
927
+ the method returns +true+.
928
+
929
+
930
+ If the action has no explicit +render+ call, it's OK to just place +export_grid_if_requested+ as the last line of the action:
931
+
932
+ def index
933
+
934
+ @tasks_grid = initialize_grid(Task,
935
+ :name => 'g1',
936
+ :enable_export_to_csv => true,
937
+ :csv_file_name => 'tasks'
938
+ )
939
+
940
+ @projects_grid = initialize_grid(Project,
941
+ :name => 'g2',
942
+ :enable_export_to_csv => true,
943
+ :csv_file_name => 'projects'
944
+ )
945
+
946
+ export_grid_if_requested
947
+ end
948
+
949
+
950
+ Otherwise, to avoid double rendering, use the return value of the method to conditionally call your +render+ :
951
+
952
+
953
+ def index
954
+
955
+ ...........
956
+
957
+ export_grid_if_requested || render(:action => 'my_template')
958
+ end
959
+
960
+
961
+ It's also possible to supply a block which will be called if no CSV export is requested:
962
+
963
+ def index
964
+
965
+ ...........
966
+
967
+ export_grid_if_requested do
968
+ render(:action => 'my_template')
969
+ end
970
+ end
971
+
972
+
973
+ If a column has to be excluded from the CSV export,
974
+ set +column+ parameter +in_csv+ to +false+:
975
+
976
+ g.column :in_csv => false do |task|
977
+ link_to('Edit', edit_task_path(task))
978
+ end
979
+
980
+ If a column must appear both in HTML and CSV, but with different output,
981
+ duplicate the column and use
982
+ parameters +in_csv+ and +in_html+ to include one of them to html output only, the other to CSV only:
983
+
984
+
985
+ # html version
986
+ g.column :column_name => 'Title', :attribute_name => 'title', :in_csv => false do |task|
987
+ link_to('Edit', edit_task_path(task.title))
988
+ end
989
+ # plain text version
990
+ g.column :column_name => 'Title', :in_html => false do |task|
991
+ task.title
992
+ end
993
+
994
+ The default field separator in generated CSV is a comma, but it's possible to override this submitting a
995
+ string to the <tt>:enable_export_to_csv</tt> parameter:
996
+
997
+ @products_grid = initialize_grid(Product,
998
+ :enable_export_to_csv => ';',
999
+ :csv_file_name => 'products')
1000
+
1001
+
1002
+ === Detached Filters
1003
+
1004
+ It is possible to detach filters and place them anywhere on the page. To do so, use parameter <tt>:detach_with_id</tt> for a column whose filter needs to be detached, with an arbitrary string or a symbol value which will be used later to identify the filter. As soon as there is one column with <tt>:detach_with_id</tt>, the behavior of the +grid+ helper changes - it becomes an <i>initializer</i> of the grid and doesn't output any HTML code. To render the grid, use <tt>grid</tt> for the second time without the block. To render a detached output filter, use helper <tt>grid_filter(grid_object, detached_filter_key)</tt>:
1005
+
1006
+ <%= grid(@tasks_grid, :show_filters => :always) do |g|
1007
+
1008
+ g.column :column_name => 'Title', :attribute_name => 'title', :detach_with_id => :title_filter do |task|
1009
+ link_to('Edit', edit_task_path(task.title))
1010
+ end
1011
+
1012
+ g.column :column_name => 'Archived', :attribute_name => 'archived', :detach_with_id => :archived_filter do |task|
1013
+ task.archived? ? 'Yes' : 'No'
1014
+ end
1015
+
1016
+ g.column :column_name => 'Added', :attribute_name => 'created_at', :detach_with_id => :created_at_filter do |task|
1017
+ task.created_at.to_s(:short)
1018
+ end
1019
+
1020
+ end -%>
1021
+
1022
+ <% # rendering filter with key :title_filter %>
1023
+ <%= grid_filter @tasks_grid, :title_filter %>
1024
+
1025
+ <% # rendering filter with key :archived_filter %>
1026
+ <%= grid_filter @tasks_grid, :archived_filter %>
1027
+
1028
+ <% # rendering filter with key :created_at_filter %>
1029
+ <%= grid_filter @tasks_grid, :created_at_filter %>
1030
+
1031
+ <% # Rendering the grid body %>
1032
+ <%= grid(@tasks_grid) %>
1033
+
1034
+ It is important that the grid initializer goes first, the order of +grid_filter+ and the second call to +grid+ is of no importance.
1035
+
1036
+ Using custom submit and reset buttons together with <tt>:hide_submit_button => true</tt> and <tt>:hide_reset_button => true</tt>
1037
+ allows to completely get rid
1038
+ of the default filter row and the default icons (see section 'Submit/Reset Buttons').
1039
+
1040
+ For CSV export will continue functioning, just make sure the first call to +grid+ is still in the template of its own and
1041
+ is inside of <tt><%= %></tt>, because when CSV is requested, the first +grid+ works in the old fashioned way producing CSV formatted output.
1042
+
1043
+ This feature also works with <tt>:erb_mode => true</tt>.
1044
+
1045
+ If a column was declared with <tt>:detach_with_id</tt>, but never output with +grid_filter+, filtering the grid in development mode will result
1046
+ in an warning javascript message and the missing filter will be ignored. There is no such message in production.
1047
+
1048
+ <tt>grid</tt> parameter <tt>:show_filter</tt> must not be set to <tt>:no</tt> for detached filters to work.
1049
+
1050
+ ==== How Does It Work? (For the interested)
1051
+
1052
+ When there is at least one column with <tt>:detach_with_id</tt>, the generated HTML code is stored in a buffer, code for detached filters is stored
1053
+ in buffers of their own identified by the given IDs, and nothing is returned to the view.
1054
+ When the helper is called for the second time, the buffer outputs its content.
1055
+ In a similar fashion, the +grid_filter+ helper outputs buffers for filters.
1056
+
1057
+ === Compatibility with Rails Asset Caching
1058
+
1059
+ Helpers +names_of_wice_grid_stylesheets+ and +names_of_wice_grid_javascripts+ return names of stylesheet and javascript files and can be used with
1060
+ +stylesheet_link_tag+ and +javascript_include_tag+ with <tt>:cache => true</tt>.
1061
+ Using this trick you have to deal with the parameters correctly, mind that Prototype has to be loaded before WiceGrid javascripts:
1062
+
1063
+ <%= stylesheet_link_tag *(['core', 'modalbox'] + names_of_wice_grid_stylesheets + [ {:cache => true}]) %>
1064
+ <%= javascript_include_tag *([:defaults] + names_of_wice_grid_javascripts + [ 'ui', 'swfobject', {:cache => true}]) %>
1065
+
1066
+
1067
+ === Access to Records From Outside The Grid
1068
+
1069
+ There are two ways you can access the records outside the grid - using methods of the WiceGrid object and using callbacks.
1070
+
1071
+ ==== Accessing Records Via The WiceGrid Object
1072
+
1073
+ Method +current_page_records+ returns exactly the same list of objects displayed on page:
1074
+
1075
+ <%= grid(@tasks_grid) do |g|
1076
+ ...
1077
+ end -%>
1078
+
1079
+ <p>
1080
+ IDs of records on the current page:
1081
+ <%= @tasks_grid.current_page_records.map(&:id).to_sentence %>
1082
+ </p>
1083
+
1084
+ Method +all_pages_records+ returns a list of objects browsable through all pages with the current filters:
1085
+
1086
+ <%= grid(@tasks_grid) do |g|
1087
+ ...
1088
+ end -%>
1089
+
1090
+ <p>
1091
+ IDs of all records:
1092
+ <%= @tasks_grid.all_pages_records.map(&:id).to_sentence %>
1093
+ </p>
1094
+
1095
+ Mind that this helper results in an additional SQL query.
1096
+
1097
+
1098
+ Because of the current implementation of WiceGrid these helpers work only after the declaration of the grid in the view.
1099
+ This is due to the lazy nature of WiceGrid - the actual call to the database is made during the execution of
1100
+ the +grid+ helper, because to build the correct query columns declarations are required.
1101
+
1102
+ ==== Accessing Records Via Callbacks
1103
+
1104
+ It is possible to set up callbacks which are executed from within the plugin just after the call to the database.
1105
+ The callbacks are called before rendering the grid cells, so the results of this processing can be used in the grid.
1106
+ There are 3 ways you can set up such callbacks:
1107
+
1108
+ Via a lambda object:
1109
+
1110
+ def index
1111
+ @tasks_grid = initialize_grid(Task,
1112
+ :with_paginated_resultset => lambda do |records|
1113
+ ...
1114
+ end
1115
+ )
1116
+ end
1117
+
1118
+ Via a symbol which is the name of a controller method:
1119
+
1120
+ def index
1121
+ @tasks_grid = initialize_grid(Task,
1122
+ :with_paginated_resultset => :process_selection
1123
+ )
1124
+ end
1125
+
1126
+ def process_selection(records)
1127
+ ...
1128
+ end
1129
+
1130
+ Via a separate block:
1131
+
1132
+ def index
1133
+ @tasks_grid = initialize_grid(Task)
1134
+
1135
+ @tasks_grid.with_paginated_resultset do |records|
1136
+ ...
1137
+ end
1138
+ end
1139
+
1140
+ There are two callbacks:
1141
+
1142
+ * <tt>:with_paginated_resultset</tt> - used to process records of the current page
1143
+ * <tt>:with_resultset</tt> - used to process all records browsable through all pages with the current filters
1144
+
1145
+ While the <tt>:with_paginated_resultset</tt> callback just receives the list of records, <tt>:with_resultset</tt>
1146
+ receives a lambda object which, when called, returns the list of all records:
1147
+
1148
+
1149
+ def index
1150
+ @tasks_grid = initialize_grid(Task)
1151
+
1152
+ @tasks_grid.with_resultset do |wrapper|
1153
+ all_records = wrapper.call
1154
+ ...
1155
+ end
1156
+ end
1157
+
1158
+
1159
+ This lazy nature exists for performance reasons.
1160
+ Reading all records leads to an additional call, and there can be cases when processing all records should be triggered
1161
+ only under certain circumstances:
1162
+
1163
+ def index
1164
+ @tasks_grid = initialize_grid(Task)
1165
+
1166
+ @tasks_grid.with_resultset do |wrapper|
1167
+ if params[:process_all_records]
1168
+ all_records = wrapper.call
1169
+ ...
1170
+ end
1171
+ end
1172
+ end
1173
+
1174
+
1175
+
1176
+ == Icons
1177
+
1178
+ Icons used by the plugin are courtesy of Mark James, the creator of the SILK icon set -
1179
+ http://www.famfamfam.com/lab/icons/silk/.