wice_grid 3.5.0 → 3.6.0.pre1

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.inch.yml +3 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +181 -0
  5. data/.travis.yml +22 -0
  6. data/{CHANGELOG → CHANGELOG.md} +95 -31
  7. data/Gemfile +4 -1
  8. data/README.md +1517 -0
  9. data/Rakefile +51 -7
  10. data/{SAVED_QUERIES_HOWTO.rdoc → SAVED_QUERIES_HOWTO.md} +34 -31
  11. data/TODO.md +16 -0
  12. data/lib/generators/wice_grid/add_migration_for_serialized_queries_generator.rb +4 -6
  13. data/lib/generators/wice_grid/install_generator.rb +2 -5
  14. data/lib/generators/wice_grid/templates/create_wice_grid_serialized_queries.rb +1 -0
  15. data/lib/generators/wice_grid/templates/wice_grid_config.rb +29 -34
  16. data/lib/wice/active_record_column_wrapper.rb +36 -17
  17. data/lib/wice/columns.rb +53 -52
  18. data/lib/wice/columns/column_action.rb +11 -13
  19. data/lib/wice/columns/column_boolean.rb +9 -11
  20. data/lib/wice/columns/column_bootstrap_datepicker.rb +48 -0
  21. data/lib/wice/columns/column_custom_dropdown.rb +22 -23
  22. data/lib/wice/columns/column_float.rb +2 -6
  23. data/lib/wice/columns/column_html5_datepicker.rb +31 -0
  24. data/lib/wice/columns/column_integer.rb +9 -13
  25. data/lib/wice/columns/column_jquery_datepicker.rb +49 -0
  26. data/lib/wice/columns/column_processor_index.rb +18 -13
  27. data/lib/wice/columns/column_rails_date_helper.rb +41 -0
  28. data/lib/wice/columns/column_rails_datetime_helper.rb +40 -0
  29. data/lib/wice/columns/column_range.rb +7 -11
  30. data/lib/wice/columns/column_string.rb +24 -20
  31. data/lib/wice/columns/common_date_datetime_mixin.rb +20 -0
  32. data/lib/wice/columns/common_js_date_datetime_conditions_generator_mixin.rb +39 -0
  33. data/lib/wice/columns/common_js_date_datetime_mixin.rb +15 -0
  34. data/lib/wice/columns/{column_date.rb → common_rails_date_datetime_conditions_generator_mixin.rb} +4 -22
  35. data/lib/wice/columns/common_standard_helper_date_datetime_mixin.rb +22 -0
  36. data/lib/wice/grid_output_buffer.rb +19 -10
  37. data/lib/wice/grid_renderer.rb +146 -85
  38. data/lib/wice/helpers/bs_calendar_helpers.rb +6 -7
  39. data/lib/wice/helpers/js_calendar_helpers.rb +19 -17
  40. data/lib/wice/helpers/wice_grid_misc_view_helpers.rb +18 -18
  41. data/lib/wice/helpers/wice_grid_serialized_queries_view_helpers.rb +44 -49
  42. data/lib/wice/helpers/wice_grid_view_helpers.rb +131 -134
  43. data/lib/wice/kaminari_monkey_patching.rb +3 -1
  44. data/lib/wice/table_column_matrix.rb +23 -8
  45. data/lib/wice/wice_grid_controller.rb +12 -16
  46. data/lib/wice/wice_grid_core_ext.rb +12 -20
  47. data/lib/wice/wice_grid_misc.rb +131 -53
  48. data/lib/wice/wice_grid_serialized_queries_controller.rb +10 -11
  49. data/lib/wice/wice_grid_serialized_query.rb +4 -3
  50. data/lib/wice/wice_grid_spreadsheet.rb +19 -18
  51. data/lib/wice_grid.rb +144 -135
  52. data/spec/schema.rb +9 -0
  53. data/spec/spec_helper.rb +75 -0
  54. data/spec/support/active_record.rb +11 -0
  55. data/spec/support/wice_grid_test_config.rb +172 -0
  56. data/spec/wice/grid_output_buffer_spec.rb +41 -0
  57. data/spec/wice/table_column_matrix_spec.rb +38 -0
  58. data/spec/wice/wice_grid_misc_spec.rb +159 -0
  59. data/spec/wice/wice_grid_spreadsheet_spec.rb +14 -0
  60. data/test/readme.txt +1 -1
  61. data/vendor/assets/javascripts/wice_grid_init.js.coffee +14 -8
  62. data/vendor/assets/stylesheets/wice_grid.scss +84 -0
  63. data/wice_grid.gemspec +32 -16
  64. metadata +217 -25
  65. data/README.rdoc +0 -1325
  66. data/lib/generators/wice_grid/templates/wice_grid.scss +0 -140
  67. data/lib/wice/columns/column_datetime.rb +0 -171
  68. data/vendor/assets/images/icons/grid/arrow_down.gif +0 -0
  69. data/vendor/assets/images/icons/grid/arrow_up.gif +0 -0
  70. data/vendor/assets/images/icons/grid/calendar_view_month.png +0 -0
  71. data/vendor/assets/images/icons/grid/collapse.gif +0 -0
  72. data/vendor/assets/images/icons/grid/delete.png +0 -0
  73. data/vendor/assets/images/icons/grid/expand.gif +0 -0
  74. data/vendor/assets/images/icons/grid/page_white_excel.png +0 -0
  75. data/vendor/assets/images/icons/grid/page_white_find.png +0 -0
  76. data/vendor/assets/images/icons/grid/table.png +0 -0
  77. data/vendor/assets/images/icons/grid/table_refresh.png +0 -0
  78. data/vendor/assets/images/icons/grid/tick_all.png +0 -0
  79. data/vendor/assets/images/icons/grid/untick_all.png +0 -0
data/README.rdoc DELETED
@@ -1,1325 +0,0 @@
1
- = WiceGrid
2
-
3
- Version:: 3.5.0
4
- Author:: Yuri Leikind
5
- Sources:: https://github.com/leikind/wice_grid/
6
- Examples online:: http://wicegrid.herokuapp.com
7
- Email:: "Yuri Leikind" <yuri.leikind at gmail dot com>
8
-
9
-
10
-
11
- == Intro
12
-
13
- WiceGrid is a Rails grid plugin.
14
-
15
- One of the goals of this plugin was to allow the programmer to define the contents of the cell on their
16
- own, just like one does when rendering a collection via a simple table (and this is what differentiates
17
- WiceGrid from various scaffolding solutions), but automate implementation of filters, ordering,
18
- paginations, CSV export, and so on. Ruby blocks provide an elegant means for this.
19
-
20
-
21
- WiceGrid builds the call to the ActiveRecord layer for you and creates a table view with the results
22
- of the call including:
23
-
24
- * pagination
25
- * sortable columns
26
- * filtering by multiple columns
27
- * CSV export
28
- * saved queries
29
-
30
- Filters are added automatically according to the type of the underlying DB column. Filtering by more
31
- than one column at the same time is possible. More than one such grid can appear on a page, and
32
- manipulations with one grid do not have any impact on others.
33
-
34
- WiceGrid does not take a collection as an input, it works directly with ActiveRecord.
35
-
36
- WiceGrid does not use XHR calls to reload itself, instead simple GET requests are used for this,
37
- nevertheless, all other page parameters are respected and preserved. WiceGrid works well with Turbolinks.
38
-
39
- WiceGrid views do not contain forms so you can include it in your own forms.
40
-
41
- WiceGrid is known to work with MySQL and Postgres.
42
-
43
-
44
-
45
- === Examples
46
-
47
- This tutorial is accompanied by a sample application with WiceGrid examples which you can browse online:
48
- http://wicegrid.herokuapp.com, or just view the code: https://github.com/leikind/wice_grid_testbed.
49
-
50
-
51
-
52
- == Requirements and Rails versions
53
-
54
- For rails 2 use version 0.6 in {the master branch}[https://github.com/leikind/wice_grid/tree/master].
55
- That branch is hardly supported.
56
-
57
- The main supported branch is +rails3+. Latest Rails 3.2.x and Rails 4.x.x are supported in this branch.
58
-
59
- If you need to use the plugin in with Rails 3.0.x and 3.1.x versions, please use WiceGrid version 3.0.4.
60
-
61
- WiceGrid relies on jQuery.
62
-
63
- If you need a JS Datepicker, WiceGrid supports jQuery Datepicker or
64
- {Bootstrap Datepicker}[https://github.com/Nerian/bootstrap-datepicker-rails], so you might need one of
65
- those. See section Installation for details on how to use datepickers.
66
-
67
- WARNING: Since 3.2.pre2 WiceGrid is not compatible with +will_paginate+ because internally it uses
68
- +kaminari+ for pagination, and +kaminari+ is not compatible with +will_paginate+!
69
-
70
-
71
- == Installation
72
-
73
- Add the following to your Gemfile:
74
-
75
- gem "wice_grid", '3.5.0'
76
-
77
- and run the +bundle+ command.
78
-
79
- Run the generator:
80
-
81
- rails g wice_grid:install
82
-
83
- This adds the config file <tt>wice_grid_config.rb</tt> to <tt>config/initializers/</tt>, the locale file
84
- <tt>wice_grid.yml</tt> to <tt>config/locales/</tt>, and the styles file <tt>wice_grid.scss</tt> to
85
- <tt>app/assets/stylesheets/</tt>.
86
-
87
- Require WiceGrid javascript in your js index file:
88
-
89
- //= require wice_grid
90
-
91
- Make sure jQuery is loaded. If the application uses Date and DateTime filters, you have to install
92
- jQuery Datepicker by yourself. You can also use
93
- {Bootstrap Datepicker}[https://github.com/Nerian/bootstrap-datepicker-rails].
94
-
95
- Here is an example of +application.js+ if jquery.ui.datepicker is used:
96
- //= require jquery
97
- //= require jquery_ujs
98
- //= require jquery-ui
99
- //= require wice_grid
100
- //= require jquery.ui.datepicker
101
- //= require_tree .
102
-
103
- Here is +application.js+ if {Bootstrap Datepicker}[https://github.com/Nerian/bootstrap-datepicker-rails] is used:
104
- //= require jquery
105
- //= require jquery_ujs
106
- //= require jquery-ui
107
- //= require wice_grid
108
- //= require bootstrap-datepicker
109
- //= require_tree .
110
-
111
- WiceGrid provides some very basic styles, not specifying exactly how the table should look like, but if
112
- the application uses Twitter Bootstrap, the markup generated by WiceGrid will have correct classes and
113
- will fit nicely. Generally it is advised to modify WiceGrid css to match the application style.
114
-
115
-
116
- == Basics
117
-
118
- The simplest example of a WiceGrid for one simple DB table called ApplicationAccount is the following:
119
-
120
- Controller:
121
-
122
- @tasks_grid = initialize_grid(Task)
123
-
124
- It is also possible to use an ActiveRecord::Relation instance as the first argument:
125
-
126
- @tasks_grid = initialize_grid(Task.where(active: true))
127
-
128
- View:
129
-
130
- <%= grid(@tasks_grid) do |g|
131
-
132
- g.column do |task|
133
- task.id
134
- end
135
-
136
- g.column do |task|
137
- task.title
138
- end
139
-
140
- g.column do |task|
141
- task.description
142
- end
143
-
144
- g.column do |task|
145
- task.archived? ? 'Yes' : 'No'
146
- end
147
-
148
- g.column do |task|
149
- link_to('Edit', edit_task_path(task))
150
- end
151
- end -%>
152
-
153
- Code <tt>g.column do |task| ... end</tt>
154
- defines everything related to a column in the resulting view table including column names, sorting,
155
- filtering, the content of the column cells, etc. The return value of the block is the table cell content.
156
-
157
- Column names are defined with parameter +:name+:
158
-
159
- <%= grid(@tasks_grid) do |g|
160
-
161
- g.column name: 'ID' do |task|
162
- task.id
163
- end
164
-
165
- g.column name: 'Title' do |task|
166
- task.title
167
- end
168
-
169
- g.column name: 'Description' do |task|
170
- task.description
171
- end
172
-
173
- g.column name: 'Archived' do |task|
174
- task.archived? ? 'Yes' : 'No'
175
- end
176
-
177
- g.column do |task|
178
- link_to('Edit', edit_task_path(task))
179
- end
180
- end -%>
181
-
182
- To add filtering and ordering, declare to which column in the underlying database table(s) the view
183
- column corresponds using parameter +:attribute+:
184
-
185
- <%= grid(@tasks_grid) do |g|
186
-
187
- g.column name: 'ID', attribute: 'id' do |task|
188
- task.id
189
- end
190
-
191
- g.column name: 'Title', attribute: 'title' do |task|
192
- task.title
193
- end
194
-
195
- g.column name: 'Description', attribute: 'description' do |task|
196
- task.description
197
- end
198
-
199
- g.column name: 'Archived', attribute: 'archived' do |task|
200
- task.archived? ? 'Yes' : 'No'
201
- end
202
-
203
- g.column do |task|
204
- link_to('Edit', edit_task_path(task))
205
- end
206
- end -%>
207
-
208
- This will add sorting links and filters for columns +Username+ and +Active+. The plugin automatically
209
- creates filters according to the type of the database column. In the above example a text field will be
210
- created for column Title (title is a string), for column +Archived+ a dropdown filter will be created
211
- with options 'Yes', 'No', and '--', and for the integer ID two short text fields are added which can
212
- contain the numeric range (more than, less than).
213
-
214
- It is important to remember that +:attribute+ is the name of the database column, not a model attribute.
215
- Of course, all database columns have corresponding model attributes, but not all model attributes map to
216
- columns in the same table with the same name.
217
-
218
- Read more about available filters in the documentation for the column method.
219
-
220
- Read the section about custom dropdown filters for more advanced filters.
221
-
222
- For columns like
223
-
224
- g.column name: 'Title', attribute: 'title' do |task|
225
- task.title
226
- end
227
-
228
- where the block contains just a call to the same attribute declared by :attribute, the block can be
229
- omitted:
230
-
231
- <%= grid(@tasks_grid) do |g|
232
-
233
- g.column name: 'ID', attribute: 'id'
234
-
235
- g.column name: 'Title', attribute: 'title'
236
-
237
- g.column name: 'Description', attribute: 'description'
238
-
239
- g.column name: 'Archived', attribute: 'archived' do |task|
240
- task.archived? ? 'Yes' : 'No'
241
- end
242
-
243
- g.column do |task|
244
- link_to('Edit', edit_task_path(task))
245
- end
246
- end -%>
247
-
248
-
249
- In this case +name+ will be used as the method name to send to the ActiveRecord instance.
250
-
251
- If only ordering is needed, and no filter, we can turn off filters using +:filter+ :
252
-
253
- g.column name: 'ID', attribute: 'id', filter: false
254
-
255
- If no ordering links are needed, use <tt>ordering: false</tt>:
256
-
257
- g.column name: 'Added', attribute: 'created_at', ordering: false
258
-
259
- It is important to understand that it is up to the developer to make sure that the value returned by a
260
- column block (the content of a cell) corresponds to the underlying database column specified by
261
- +:attribute+ (and +:model+ discussed below).
262
-
263
-
264
- == Rendering filter panel
265
-
266
- The filter panel can be shown and hidden clicking the icon with binoculars.
267
-
268
- The way the filter panel is shown after the page is loaded is controlled via parameter
269
- +:show_filters+ of the +grid+ helper.
270
- Possible values are:
271
-
272
- * +:when_filtered+ - the filter is shown when the current table is the result of filtering
273
- * +:always+ - always show the filter
274
- * +:no+ - never show the filter
275
-
276
- Example:
277
-
278
- <%= grid(@tasks_grid, show_filters: :always) do |g|
279
- ......
280
- end -%>
281
-
282
-
283
- Filter related icons (filter icon, reset icon, show/hide icon) are placed in the header of the last
284
- column if it doesn't have any filter or a column name, otherwise an additional table column is added.
285
- To always place the icons in the additional column, set
286
- <tt>Wice::Defaults::REUSE_LAST_COLUMN_FOR_FILTER_ICONS</tt> to +false+ in the configuration file.
287
-
288
-
289
- == Initial Ordering
290
-
291
- Initializing the grid we can also define the column by which the record will be ordered <em>on the first
292
- rendering of the grid</em>, when the user has not set their ordering setting by clicking the column label,
293
- and the order direction:
294
-
295
- @tasks_grid = initialize_grid(Task,
296
- order: 'tasks.title',
297
- order_direction: 'desc'
298
- )
299
-
300
- == Records Per Page
301
-
302
- The number of rows per page is set with +:per_page+:
303
-
304
- @tasks_grid = initialize_grid(Task, per_page: 40)
305
-
306
- == Conditions
307
-
308
- The +initialize_grid+ method supports a +:conditions+ parameter which is passed on to the underlying
309
- ActiveRecord, so it can be in any format processable by ActiveRecord:
310
-
311
- @tasks_grid = initialize_grid(Task,
312
- conditions: ["archived = false and estimated_time > ?", 100]
313
- )
314
-
315
- @tasks_grid = initialize_grid(Task,
316
- include: :project,
317
- conditions: {archived: false, project: {active: true}}
318
- )
319
-
320
-
321
-
322
- A good example is substituting a common pattern like
323
-
324
- @user_groups = @portal_application.user_groups
325
-
326
- with WiceGrid code:
327
-
328
- @user_groups_grid = initialize_grid(
329
- UserGroup,
330
- conditions: ['portal_application_id = ?', @portal_application]
331
- )
332
-
333
- Alternatively, instead of a Class object as the first parameter, you can use ActiveRecord::Relation:
334
-
335
- @tasks_grid = initialize_grid(
336
- Task.where(archived: false, projects: {active: true}).joins(:project)
337
- )
338
-
339
-
340
- Please note that though all queries inside of WiceGrid are run without the default scope, if you use an
341
- ActiveRecord::Relation instance to initialize grid, it will already include the default scope. Thus you
342
- might consider using +unscoped+:
343
-
344
- @tasks_grid = initialize_grid(
345
- Task.unscoped.where(archived: false, projects: {active: true}).joins(:project)
346
- )
347
-
348
- == Queries with join tables
349
-
350
- WiceGrid also supports ActiveRecord's +:joins+ and +:include+.
351
-
352
- @products_grid = initialize_grid(Product,
353
- include: :category,
354
- order: 'products.name',
355
- per_page: 20
356
- )
357
-
358
- Note that if we want to order initially by a column from a joined table we have to specify the table and
359
- the column name with the sql dot notation, that is, +products.name+.
360
-
361
- To show columns of joined tables in the view table, the ActiveRecord model class name has to be specified,
362
- that corresponds to the joined table:
363
-
364
- <%= grid(@products_grid) do |g|
365
- g.column name: 'Product Name', attribute: 'name' do |product| # primary table
366
- link_to(product.name, product_path(product))
367
- end
368
-
369
- g.column name: 'Category', attribute: 'name', model: Category do |product| # joined table
370
- product.category.name
371
- end
372
- %>
373
-
374
- Please note that the blockless definition of the column only works with columns from the main table and it
375
- won't work with columns with <tt>:model</tt>
376
-
377
- == Joined associations referring to the same table
378
-
379
- In case there are two joined associations both referring to the same table, ActiveRecord constructs a query
380
- where the second join provides an alias for the joined table. To enable WiceGrid to order and filter by
381
- columns belonging to different associations but originating from the same table, set <tt>:table_alias</tt>
382
- to this alias:
383
-
384
- Model:
385
-
386
- class Project < ActiveRecord::Base
387
- belongs_to :customer, class_name: 'Company'
388
- belongs_to :supplier, class_name: 'Company'
389
- end
390
-
391
- Controller:
392
-
393
- @projects_grid = initialize_grid(Project, include: [:customer, :supplier])
394
-
395
-
396
- View:
397
-
398
- <%= grid(@projects_grid, show_filters: :always) do |g|
399
-
400
- g.column name: 'Project Name', attribute: 'name'
401
-
402
- g.column name: 'Customer company', model: 'Company', attribute: 'name' do |task|
403
- task.customer.name if task.customer
404
- end
405
-
406
- g.column name: 'Supplier company', model: 'Company', attribute: 'name', table_alias: 'suppliers_projects' do |task|
407
- task.supplier.name if task.supplier
408
- end
409
-
410
- end -%>
411
-
412
-
413
- == More than one grid on a page
414
-
415
- It is possible to use more that one grid on a page, each with its own state. To do so, you must specify the
416
- name of the grid in +initialize_grid+ using parameter <tt>:name</tt>.
417
-
418
- The name serves as the base name for HTTP parameters, DOM IDs, etc, so it is important that all grids on a
419
- page have different names. The default name is 'grid'.
420
-
421
- The name can only contain alphanumeric characters.
422
-
423
- @projects_grid = initialize_grid(Project, name: 'g1')
424
- @tasks_grid = initialize_grid(Task, name: 'g2')
425
-
426
-
427
- == Custom Ordering
428
-
429
- It is possible to change the way results are ordered injecting a chunk of SQL code, for example, use
430
- <tt>ORDER BY INET_ATON(ip_address)</tt> instead of <tt>ORDER BY ip_address</tt>.
431
-
432
- To do so, provide parameter <tt>:custom_order</tt> in the initialization of the grid with a hash where
433
- keys are fully qualified names of database columns, and values the required chunks of SQL to use in the
434
- <tt>ORDER BY</tt> clause.
435
-
436
- For example:
437
-
438
- @hosts_grid = initialize_grid(Host,
439
- custom_order: {
440
- 'hosts.ip_address' => 'INET_ATON(hosts.ip_address)'
441
- })
442
-
443
-
444
- It is possible to use the '?' character instead of the name of the column in the hash value:
445
-
446
- @hosts_grid = initialize_grid(Host,
447
- custom_order: {
448
- 'hosts.ip_address' => 'INET_ATON( ? )'
449
- })
450
-
451
- Values can also be Proc objects. The parameter supplied to such a Proc object is the name of the column:
452
-
453
- @hosts_grid = initialize_grid(Host,
454
- custom_order: {
455
- 'hosts.ip_address' => lambda{|f| "INET_ATON( #{f} )"}
456
- })
457
-
458
- == Filters
459
-
460
- Each column filter type is supported by a <tt>column processor</tt>. Each <tt>column processor</tt> is
461
- responsible for
462
-
463
- * generating HTML and supporting Javascript for the filter, input fields, dropdowns, javascript calendars, etc
464
- * converting HTTP parameters from those input fields into ActiveRelation instances
465
-
466
- By default column filters depend on the type of the underlying database column.
467
-
468
- You can override these defaults in two ways:
469
-
470
- * defining a custom filter with <tt>:custom_filter</tt>. Read more about it section "Custom dropdown filters".
471
- * overriding the <tt>column processor</tt> type with <tt>:filter_type</tt>.
472
-
473
- Which Column Processor is instantiated for which data types is defined in file
474
- <tt>lib/wice/columns/column_processor_index.rb</tt>:
475
-
476
-
477
- module Wice
478
- module Columns
479
- COLUMN_PROCESSOR_INDEX = ActiveSupport::OrderedHash[
480
- :action , 'column_action', # Special processor for action column, columns with checkboxes
481
- :text , 'column_string',
482
- :string , 'column_string',
483
- :timestamp, 'column_datetime',
484
- :datetime , 'column_datetime',
485
- :date , 'column_date',
486
- :integer , 'column_integer',
487
- :range , 'column_range',
488
- :float , 'column_float',
489
- :decimal , 'column_float',
490
- :custom , 'column_custom_dropdown', # Special processor for custom filter columns
491
- :boolean , 'column_boolean'
492
- ]
493
- end
494
- end
495
-
496
- A good example for using <tt>:filter_type</tt> to change th default is numeric columns. By default
497
- <tt>'column_integer'</tt> is instantiated for <tt>integer</tt> columns, and it renders one input field.
498
- But it is also possible to use another Column Processor called <tt>'column_range'</tt> which renders two
499
- input fields and searches for values in the given the range instead of searching for values which equal
500
- the given search term.
501
-
502
- It also possible to define and use your own column processors outside of the plugin, in you application.
503
- Read more about this in section "Defining your own external filter processors".
504
-
505
-
506
- === Custom dropdown filters
507
-
508
- It is possible to construct custom dropdown filters. A custom dropdown filter is essentially a dropdown
509
- list.
510
-
511
- Depending on the value of <tt>column</tt> parameter<tt>:custom_filter</tt> different modes are available:
512
-
513
-
514
- ==== Array of two-element arrays or a hash
515
-
516
- An array of two-element arrays or a hash are semantically identical ways of creating a custom filter.
517
-
518
- Every first item of the two-element array is used for the label of the select option while the second
519
- element is the value of the select option. In case of a hash the keys become the labels of the generated
520
- dropdown list, while the values will be values of options of the dropdown list:
521
-
522
- g.column name: 'Status', attribute: 'status',
523
- custom_filter: {'Development' => 'development', 'Testing' => 'testing', 'Production' => 'production'}
524
-
525
- g.column name: 'Status', attribute: 'status',
526
- custom_filter: [['Development', 'development'], ['Testing', 'testing'], ['Production', 'production']]
527
-
528
- It is also possible to submit a array of strings or numbers, in this case every item will be used both as
529
- the value of the select option and as its label:
530
-
531
- g.column name: 'Status', attribute: 'status', custom_filter: ['development', 'testing', 'production']
532
-
533
-
534
- ==== :auto
535
-
536
- <tt>:auto</tt> - a powerful option which populates the dropdown list with all unique values of the column
537
- specified by <tt>:attribute</tt> and <tt>:model</tt>, if present.
538
-
539
- g.column name: 'Status', attribute: 'status', custom_filter: :auto
540
-
541
- In the above example all statuses will appear in the dropdown even if they don't appear in the current
542
- resultset.
543
-
544
-
545
- ==== Custom filters and associations (joined tables)
546
-
547
- In most cases custom fields are needed for one-to-many and many-to-many associations.
548
-
549
- To correctly build a filter condition foreign keys have to be used, not the actual values rendered in the
550
- column.
551
-
552
- For example, if there is a column:
553
-
554
- g.column name: 'Project Name', attribute: 'name', model: 'Project' do |task|
555
- task.project.name if task.project
556
- end
557
-
558
- adding <tt>:custom_filter</tt> like this:
559
-
560
- g.column name: 'Project Name', attribute: 'name', model: 'Project',
561
- custom_filter: Project.find(:all).map{|pr| [pr.name, pr.name]} do |task|
562
- task.project.name if task.project
563
- end
564
-
565
- is bad style and can fail, because the resulting condition will compare the name of the project,
566
- <tt>projects.name</tt> to a string, and in some databases it is possible that different records
567
- (projects in our example) have the same name.
568
-
569
- To use filter with foreign keys, it is advised to change the declaration of the column from
570
- <tt>projects.name</tt>, to <tt>tasks.project_id</tt>, and build the dropdown with foreign keys as values:
571
-
572
-
573
- g.column name: 'Project Name', attribute: 'tasks.project_id',
574
- custom_filter: Project.find(:all).map{|pr| [pr.id, pr.name]} do |task|
575
- task.project.name if task.project
576
- end
577
-
578
- However, this will break the ordering of the column - the column will be ordered by the integer foreign
579
- key. To fix this, we can override the ordering using <tt>:custom_order</tt>:
580
-
581
- @tasks_grid = initialize_grid(Task,
582
- include: :project,
583
- custom_order: {
584
- 'tasks.project_id' => 'projects.name'
585
- }
586
- )
587
-
588
-
589
- ==== Any other symbol (method name) or an array of symbols (method names)
590
-
591
-
592
- For one symbol (different from <tt>:auto</tt>) the dropdown list is populated by all unique values returned
593
- by the method with this name sent to <em>all</em> ActiveRecord objects throughout all pages.
594
-
595
- The conditions set up by the user are ignored, that is, the records used are all those found on all pages
596
- without any filters active.
597
-
598
- For an array of symbols, the first method name is sent to the ActiveRecord object if it responds to this
599
- method, the second method name is sent to the returned value unless it is +nil+, and so on. In other
600
- words, a single symbol mode is the same as an array of symbols where the array contains just one element.
601
-
602
- g.column name: 'Version', attribute: 'expected_version_id', custom_filter: [:expected_version, :to_option] do |task|
603
- task.expected_version.name if task.expected_version
604
- end
605
-
606
-
607
- There are two important differences from <tt>:auto</tt>:
608
-
609
- 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.
610
- 2. Filtering by any option of such a custom filter will bring a non-empty list, unlike with <tt>:auto</tt>.
611
-
612
-
613
- This mode has one major drawback - this mode requires an additional query without +offset+ and +limit+
614
- clauses to instantiate _all_ ActiveRecord objects, and performance-wise it brings all the advantages of
615
- pagination to nothing. Thus, memory- and performance-wise this can be really bad for some queries and
616
- tables and should be used with care.
617
-
618
-
619
- If the final method returns a atomic value like a string or an integer, it is used for both the value and
620
- the label of the select option element:
621
-
622
- <option value="returned value">returned value</option>
623
-
624
- However, if the retuned value is a two element array, the first element is used for the option label and
625
- the second - for the value.
626
-
627
- Typically, a model method like the following:
628
-
629
- def to_option
630
- [name, id]
631
- end
632
-
633
- together with
634
-
635
- custom_filter: :to_option
636
-
637
- would do the trick:
638
-
639
- <option value="id">name</option>
640
-
641
- Alternatively, a hash with the single key-value pair can be used, where the key will be used for the
642
- label, and the key - for the value:
643
-
644
- def to_option
645
- {name => id}
646
- end
647
-
648
-
649
- ==== Special treatment of values 'null' and 'not null'
650
-
651
- Values +null+ and +not null+ in a generated custom filter are treated specially, as SQL +null+ statement
652
- and not as strings. Value +null+ is transformed into SQL condition +IS NULL+, and +not null+ into
653
- <tt>IS NOT NULL</tt>.
654
-
655
- Thus, if in a filter defined by
656
-
657
- custom_filter: {'No' => 'null', 'Yes' => 'not null', '1' => 1, '2' => '2', '3' => '3'}
658
-
659
- values '1', '2' and 'No' are selected (in a multi-select mode), this will result in the following SQL:
660
-
661
- ( table.field IN ( '1', '2' ) OR table.field IS NULL )
662
-
663
-
664
- ==== Multiple selection
665
-
666
- By default it is possible for any dropdown list to switch between single and multiple selection modes.
667
- To only allow single selection use <tt>:allow_multiple_selection</tt>:
668
-
669
-
670
- g.column name: 'Expected in version', attribute: 'expected_version_id',
671
- custom_filter: [:expected_version, :to_option], allow_multiple_selection: false do |task|
672
- ...
673
- end
674
-
675
-
676
- === Numeric Filters
677
-
678
- Before version 3.2.1 the filter used for numeric columns was a range filter with two limits. Beginning
679
- with version 3.2.1 the default is a direct comparison filter with one input field. The old range filter
680
- can still be loaded using parameter <tt>:filter_type</tt> with value <tt>:range</tt>:
681
-
682
- g.column filter_type: :range do |task|
683
- ...
684
- end
685
-
686
-
687
- === Date and DateTime Filters
688
-
689
- WiceGrid provides four ways of selecting dates and times. The default style is set in
690
- <tt>config/initializers/wice_grid_config.rb</tt> using the HELPER_STYLE constant. The available options are
691
-
692
- * <tt>:calendar</tt> (jQuery UI datepicker),
693
- * <tt>:bootstrap</tt> {Bootstrap datepicker}[https://github.com/Nerian/bootstrap-datepicker-rails],
694
- * <tt>:standard</tt>.
695
-
696
- The style can also be individually configured via the <tt>helper_style</tt> option on a Date/DateTime
697
- filter column configuration:
698
-
699
- g.column name: 'Due Date', attribute: 'due_date', helper_style: :calendar do |task|
700
- task.due_date.to_s(:short) if task.due_date
701
- end
702
-
703
- g.column name: 'Created', attribute: 'created_at', helper_style: :bootstrap do |task|
704
- task.created_at.to_s(:short)
705
- end
706
-
707
- g.column name: 'Updated', attribute: 'updated_at', helper_style: :standard do |task|
708
- task.created_at.to_s(:short)
709
- end
710
-
711
-
712
-
713
- ==== jQuery UI DatePicker <tt>(HELPER_STYLE = :calendar)</tt>
714
-
715
- By default WiceGrid uses jQuery UI datepicker[http://jqueryui.com/demos/datepicker/] for Date and DateTime
716
- filters. Because this is part of the standard jQuery UI codebase, it is not bundled together with the
717
- plugin, and it is the responsibility of the programmer to include all necessary assets including
718
- localization files if the application is multilingual.
719
-
720
- jQuery UI datepicker does not have any time related controls, and when dealing with DateTime filters, the
721
- time value is ignored.
722
-
723
- Constants +DATE_FORMAT+ and +DATETIME_FORMAT+ in the configuration file define the format of dates the
724
- user will see, as well as the format of the string sent in a HTTP parameter. If you change the formats,
725
- make sure that lamdbas defined in +DATETIME_PARSER+ and +DATE_PARSER+ return valid DateTime and Date
726
- objects.
727
-
728
- jQuery +datepicker+ uses a different format flavor, therefore there is an additional constant
729
- +DATE_FORMAT_JQUERY+. While +DATE_FORMAT_JQUERY+ is fed to +datepicker+, +DATE_FORMAT+ is still used
730
- for presenting initial date values in filters, so make sure that +DATE_FORMAT_JQUERY+ and +DATE_FORMAT+
731
- result in an identical date representation.
732
-
733
- Constant +DATEPICKER_YEAR_RANGE+ defines the range of years in the Datepicker year dropdown. Alternatively,
734
- you can always change this range dynamically with the following javascript:
735
-
736
- $( ".hasDatepicker" ).datepicker( "option", "yearRange", "2000:2042" );
737
-
738
-
739
- ==== jQuery UI DatePicker <tt>(HELPER_STYLE = :bootstrap)</tt>
740
-
741
- WiceGrid also supports {Bootstrap Datepicker}[https://github.com/Nerian/bootstrap-datepicker-rails].
742
-
743
- ==== Rails standard input fields <tt>(HELPER_STYLE = :standard)</tt>
744
-
745
- Another option is standard Rails helpers for date fields, these are separate select fields for years,
746
- months and days (also for hour and minute if it is a datetime field).
747
-
748
- == Detached Filters
749
-
750
- Filters can also be detached from the grid table and placed anywhere on page.
751
-
752
- This is a 3-step process.
753
-
754
- First, define the grid with helper +define_grid+ instead of +grid+. Everything should be done the same way
755
- as with +grid+, but every column which will have an external filter, add
756
- <tt>detach_with_id: :some_filter_name+</tt> in the column definition. The value of +:detach_with_id+ is an
757
- arbitrary string or a symbol value which will be used later to identify the filter.
758
-
759
- <%= define_grid(@tasks_grid, show_filters: :always) do |g|
760
-
761
- g.column name: 'Title', attribute: 'title', detach_with_id: :title_filter do |task|
762
- link_to('Edit', edit_task_path(task.title))
763
- end
764
-
765
- g.column name: 'Archived', attribute: 'archived', detach_with_id: :archived_filter do |task|
766
- task.archived? ? 'Yes' : 'No'
767
- end
768
-
769
- g.column name: 'Added', attribute: 'created_at', detach_with_id: :created_at_filter do |task|
770
- task.created_at.to_s(:short)
771
- end
772
-
773
- end -%>
774
-
775
-
776
- Then, use <tt>grid_filter(grid, :some_filter_name)</tt> to render filters:
777
-
778
- <% # rendering filter with key :title_filter %>
779
- <%= grid_filter @tasks_grid, :title_filter %>
780
-
781
- <% # rendering filter with key :archived_filter %>
782
- <%= grid_filter @tasks_grid, :archived_filter %>
783
-
784
- <% # rendering filter with key :created_at_filter %>
785
- <%= grid_filter @tasks_grid, :created_at_filter %>
786
-
787
- <% # Rendering the grid body %>
788
- <%= grid(@tasks_grid) %>
789
-
790
-
791
- Finally, use <tt>render_grid(@grid)</tt> to actually output the grid table.
792
-
793
-
794
- Using custom submit and reset buttons together with <tt>hide_submit_button: true</tt> and
795
- <tt>hide_reset_button: true</tt> allows to completely get rid of the default filter row and the default
796
- icons (see section 'Submit/Reset Buttons').
797
-
798
-
799
- If a column was declared with <tt>:detach_with_id</tt>, but never output with +grid_filter+, filtering
800
- the grid in development mode will result in an warning javascript message and the missing filter will be
801
- ignored. There is no such message in production.
802
-
803
-
804
- === Defining your own external filter processors
805
-
806
-
807
- It possible to define and use your own column processors outside of the plugin, in you application.
808
-
809
- The first step is to edit <tt>Wice::Defaults::ADDITIONAL_COLUMN_PROCESSORS</tt> in
810
- <tt>wice_grid_config.rb</tt>:
811
-
812
-
813
- Wice::Defaults::ADDITIONAL_COLUMN_PROCESSORS = {
814
- my_own_filter: ['ViewColumnMyOwnFilter', 'ConditionsGeneratorMyOwnFilter'],
815
- another_filter: ['ViewColumnAnotherFilter', 'ConditionsGeneratorAnotherFilter']
816
- }
817
-
818
- The first element in the two-item array is the name of a class responsible for rendering
819
- the filter view. The second element is the name of a class responsible for processing
820
- filter parameters.
821
-
822
- For examples of these two classes look at the existing column processors in <tt>lib/wice/columns/</tt>
823
-
824
- The structure of these two classes is as follows:
825
-
826
- class ViewColumnMyOwnFilter < Wice::Columns::ViewColumn
827
-
828
- def render_filter_internal(params)
829
- ...
830
- end
831
-
832
- def yield_declaration_of_column_filter
833
- {
834
- templates: [...],
835
- ids: [...]
836
- }
837
- end
838
- end
839
-
840
-
841
- class ConditionsGeneratorMyOwnFilter < Wice::Columns::ConditionsGeneratorColumn
842
-
843
- def generate_conditions(table_name, opts)
844
- ...
845
- end
846
-
847
- end
848
-
849
- To use an external column processor use <tt>:filter_type</tt> in a column definition:
850
-
851
- column name: 'name', attribute: 'attribute', filter_type: :my_own_filter do |rec|
852
- ...
853
- end
854
-
855
- == Defaults
856
-
857
- Default values like can be changed in <tt>config/initializers/wice_grid_config.rb</tt>.
858
-
859
- == Submit/Reset buttons
860
- Instead of using default Submit and Reset icons you can use external HTML elements to trigger
861
- these actions. Add a button or any other clickable HTML element with class
862
- +wg-external-submit-button+ or +wg-external-reset-button+, and attribute +data-grid-name+
863
- whose value is the name of the grid:
864
-
865
- <button class="wg-external-submit-button" data-grid-name="grid">Submit</button>
866
- <button class="wg-external-reset-button" data-grid-name="grid">Reset</button>
867
-
868
- To hide the default icons use <tt>hide_submit_button: true</tt> and
869
- <tt>hide_reset_button: true</tt> in the +grid+ helper.
870
-
871
-
872
-
873
-
874
- == Auto-reloading filters
875
-
876
- It is possible to configure a grid to reload itself once a filter has been changed. It works with all
877
- filter types including the JS calendar, the only exception is the standard Rails date/datetime filters.
878
-
879
- Use option <tt>:auto_reload</tt> in the column definiton:
880
-
881
-
882
- <%= grid(@tasks_grid, show_filters: :always, hide_submit_button: true) do |g|
883
-
884
- # String
885
- g.column name: 'Title', attribute: 'title', auto_reload: true
886
-
887
- # Boolean
888
- g.column name: 'Archived', attribute: 'archived', auto_reload: true
889
-
890
- # Custom (dropdown)
891
- g.column name: 'Status', attribute: 'status_id', custom_filter: Status.to_dropdown, auto_reload: true do |task|
892
- task.status.name if task.status
893
- end
894
-
895
- # Datetime
896
- g.column name: 'Added', attribute: 'created_at', auto_reload: true, helper_style: :calendar do |task|
897
- task.created_at.to_s(:short)
898
- end
899
-
900
- end -%>
901
-
902
- To make this behavior default change constant +AUTO_RELOAD+ in the configuration file.
903
-
904
- == Styling the grid
905
-
906
-
907
- === Adding classes and styles
908
-
909
- The +grid+ helper accepts parameter <tt>:html</tt> which is a hash of HTML attributes for the table tag.
910
-
911
- Another +grid+ parameter is <tt>header_tr_html</tt> which is a hash of HTML attributes to
912
- be added to the first +tr+ tag (or two first +tr+'s if the filter row is present).
913
-
914
- <tt>:html</tt> is a parameter for the +column+ method setting HTML attributes of +td+ tags for a certain column.
915
-
916
- === Adding classes and styles dynamically
917
-
918
- WiceGrid offers ways to dynamically add classes and styles to +TR+ and +TD+ based on the current ActiveRecord instance.
919
-
920
-
921
- For <tt><TD></tt>, let the +column+ return an array where the first item is the usual
922
- string output whole the second is a hash of HTML attributes to be added for the
923
- <tt><td></tt> tag of the current cell:
924
-
925
- g.column do |portal_application|
926
- css_class = portal_application.public? ? 'public' : 'private'
927
- [portal_application.name, {class: css_class}]
928
- end
929
-
930
- For adding classes/styles to <tt><TR></tt> use special clause +row_attributes+ ,
931
- similar to +column+, only returning a hash:
932
-
933
- <%= grid(@versions_grid) do |g|
934
- g.row_attributes do |version|
935
- if version.in_production?
936
- {style: 'background-color: rgb(255, 255, 204);'}
937
- end
938
- end
939
-
940
- g.column{|version| ... }
941
- g.column{|version| ... }
942
- end -%>
943
-
944
- Naturally, there can be only one +row_attributes+ definition for a WiceGrid instance.
945
-
946
- Various classes do not overwrite each other, instead, they are concatenated.
947
-
948
-
949
- == Adding rows to the grid
950
-
951
- It is possible to add your own handcrafted HTML after and/or before each grid row.
952
- This works similar to +row_attributes+, by adding blocks +after_row+, +before_row+, and +last_row+:
953
-
954
- <%= grid(@tasks_grid) do |g|
955
- g.before_row do |task, number_of_columns|
956
- if task.active?
957
- "<tr><td colspan=\"10\">Custom line for #{t.name}</td></tr>" # this would add a row
958
- # before every active task row
959
- else
960
- nil
961
- end
962
- end
963
-
964
- g.last_row do |number_of_columns| # This row will always be added to the bottom of the grid
965
- content_tag(:tr,
966
- content_tag(:td,
967
- 'Last row',
968
- colspan: 10),
969
- class: 'last_row')
970
- end
971
-
972
- .......
973
- end %>
974
-
975
- It is up for the developer to return the correct HTML code, or return +nil+ if no row is needed for this record.
976
- Naturally, there is only one +before_row+ definition and one +after_row+ definition for a WiceGrid instance.
977
-
978
- The second variable injected into to <tt>before_row</tt> and <tt>after_row</tt> block, and the first parameter injected
979
- into the <tt>last_row</tt> is the number of columns in the current grid.
980
-
981
- == Rendering a grid without records
982
-
983
- If the grid does not contain any records to show, it is possible show some alternative view instead of
984
- an empty grid. Bear in mind that if the user sets up the filters in such a way that the selection of
985
- records is empty, this will still render the grid and it will be possible to reset the grid clicking
986
- on the Reset button. Thus, this only works if the initial number of records is 0.
987
-
988
- <%= grid(@grid) do |g|
989
-
990
- g.blank_slate do
991
- "There are no records"
992
- end
993
-
994
- g.column do |product|
995
- ...
996
- end
997
- end -%>
998
-
999
- There are two alternative ways to do the same, submitting a string to +blank_slate+:
1000
-
1001
- g.blank_slate "some text to be rendered"
1002
-
1003
- Or a partial:
1004
-
1005
- g.blank_slate partial: "partial_name"
1006
-
1007
-
1008
- == Action Column
1009
-
1010
- It is possible to add a column with checkboxes for each record. This is useful for actions with multiple records,
1011
- for example, deleting selected records. Please note that +action_column+ only creates the checkboxes and the
1012
- 'Select All' and 'Deselect All' buttons, and the form itself as well as processing the parameters should be
1013
- taken care of by the application code.
1014
-
1015
- <%= grid(@tasks_grid, show_filters: :always) do |g|
1016
-
1017
- ...
1018
-
1019
- g.action_column
1020
-
1021
- ...
1022
-
1023
- end -%>
1024
-
1025
- By default the name of the HTTP parameter follows pattern <tt>"#{grid_name}[#{param_name}][]"</tt>, thus
1026
- <tt>params[grid_name][param_name]</tt> will contain an array of object IDs.
1027
-
1028
-
1029
- You can hide a certain action checkbox if you add the usual block to +g.action_column+, just like with the
1030
- +g.column+ definition. If the block returns +nil+ or +false+ no checkbox will be rendered.
1031
-
1032
- <%= grid(@tasks_grid, show_filters: :always) do |g|
1033
-
1034
- ...
1035
-
1036
- g.action_column do |task|
1037
- task.finished?
1038
- end
1039
-
1040
- ...
1041
-
1042
- end -%>
1043
-
1044
-
1045
-
1046
- WiceGrid is form-friendly: submitting grid in a form retains the state of the form.
1047
-
1048
-
1049
-
1050
- == Integration of the grid with other forms on page
1051
-
1052
- Imagine that the user should be able to change the behavior of the grid using some other control
1053
- on the page, and not a grid filter.
1054
-
1055
- For example, on a page showing tasks, change between 'Show active tasks' to 'Show archived tasks' using a dropdown box.
1056
- WiceGrid allows to keep the status of the grid with all the filtering and sorting using helper
1057
- +dump_filter_parameters_as_hidden_fields+ which takes a grid object and dumps
1058
- all current sorting and filtering parameters as hidden fields. Just include
1059
- <tt>dump_filter_parameters_as_hidden_fields(@grid)</tt> inside your form, and the newly rendered grid will keep ordering and filtering.
1060
-
1061
- <% form_tag('', method: :get) do %>
1062
- <%= dump_filter_parameters_as_hidden_fields(@tasks_grid) %>
1063
- <%= select_tag 'archived',
1064
- options_for_select([['View active tasks', 0], ['View archived tasks', 1]], @archived ? 1 : 0),
1065
- onchange: 'this.form.submit()' %>
1066
- <% end -%>
1067
-
1068
-
1069
-
1070
- == Show All Records
1071
-
1072
- It is possible to switch to the All Records mode clicking on link "show all" in the bottom right corner.
1073
- This functionality should be used with care. To turn this mode off for all grid instances,
1074
- change constant +ALLOW_SHOWING_ALL_RECORDS+ in <tt>config/initializers/wice_grid_config.rb</tt> to
1075
- +false+. To do so for a specific grid, use initializer parameter <tt>:allow_showing_all_records</tt>.
1076
-
1077
- Configuration constant +START_SHOWING_WARNING_FROM+ sets the threshold number of all records after
1078
- which clicking on the link results in a javascript confirmation dialog.
1079
-
1080
-
1081
- == CSV Export
1082
-
1083
- It is possible to export the data displayed on a grid to a CSV file. The dumped data is the current resultset
1084
- with all the current filters and sorting applied, only without the pagination constraint (i.e. all pages).
1085
-
1086
- To enable CSV export add parameters +enable_export_to_csv+ and +csv_file_name+ to the initialization of the grid:
1087
-
1088
- @projects_grid = initialize_grid(Project,
1089
- include: [:customer, :supplier],
1090
- name: 'g2',
1091
- enable_export_to_csv: true,
1092
- csv_file_name: 'projects'
1093
- )
1094
-
1095
- +csv_file_name+ is the name of the downloaded file. This parameter is optional, if it is missing, the name of
1096
- the grid is used instead. The export icon will appear at the bottom right corner of the grid.
1097
-
1098
- Next, each grid view helper should be placed in a partial of its own, requiring it from the master
1099
- template for the usual flow. There must be no HTML or ERB code in this partial except for the grid helper.
1100
-
1101
- By convention the name of such a partial follows the following pattern:
1102
-
1103
- _GRID_NAME_grid.html.erb
1104
-
1105
- In other words, a grid named +tasks+ is expected to be found in a template called
1106
- <tt>_tasks_grid.html.erb</tt> (remember that the default name of grids is '+grid+'.)
1107
-
1108
- Next, method +export_grid_if_requested+ should be added to the end of each action
1109
- containing grids with enabled CSV export.
1110
-
1111
- +export_grid_if_requested+ intercepts CSV export requests and evaluates the partial with the required grid helper.
1112
-
1113
- The naming convention for grid partials can be easily overridden by supplying a hash parameter
1114
- to +export_grid_if_requested+ where each key is the name of a grid, and the value is the name of
1115
- the template (like it is specified for +render+, i.e. without '_' and extensions):
1116
-
1117
-
1118
- export_grid_if_requested('g1' => 'tasks_grid', 'g2' => 'projects_grid')
1119
-
1120
- If the request is not a CSV export request, +export_grid_if_requested+ does nothing and returns
1121
- +false+, if it is a CSV export request, the method returns +true+.
1122
-
1123
-
1124
- If the action has no explicit +render+ call, it's OK to just place +export_grid_if_requested+
1125
- as the last line of the action:
1126
-
1127
- def index
1128
-
1129
- @tasks_grid = initialize_grid(Task,
1130
- name: 'g1',
1131
- enable_export_to_csv: true,
1132
- csv_file_name: 'tasks'
1133
- )
1134
-
1135
- @projects_grid = initialize_grid(Project,
1136
- name: 'g2',
1137
- enable_export_to_csv: true,
1138
- csv_file_name: 'projects'
1139
- )
1140
-
1141
- export_grid_if_requested
1142
- end
1143
-
1144
-
1145
- Otherwise, to avoid double rendering, use the return value of the method to conditionally call your +render+ :
1146
-
1147
-
1148
- def index
1149
-
1150
- ...........
1151
-
1152
- export_grid_if_requested || render(action: 'my_template')
1153
- end
1154
-
1155
-
1156
- It's also possible to supply a block which will be called if no CSV export is requested:
1157
-
1158
- def index
1159
-
1160
- ...........
1161
-
1162
- export_grid_if_requested do
1163
- render(action: 'my_template')
1164
- end
1165
- end
1166
-
1167
-
1168
- If a column has to be excluded from the CSV export,
1169
- set +column+ parameter +in_csv+ to +false+:
1170
-
1171
- g.column in_csv: false do |task|
1172
- link_to('Edit', edit_task_path(task))
1173
- end
1174
-
1175
- If a column must appear both in HTML and CSV, but with different output, duplicate the column and use
1176
- parameters +in_csv+ and +in_html+ to include one of them to html output only, the other to CSV only:
1177
-
1178
-
1179
- # html version
1180
- g.column name: 'Title', attribute: 'title', in_csv: false do |task|
1181
- link_to('Edit', edit_task_path(task.title))
1182
- end
1183
- # plain text version
1184
- g.column name: 'Title', in_html: false do |task|
1185
- task.title
1186
- end
1187
-
1188
- The default field separator in generated CSV is a comma, but it's possible to override it:
1189
-
1190
- @products_grid = initialize_grid(Product,
1191
- enable_export_to_csv: true,
1192
- csv_field_separator: ';',
1193
- csv_file_name: 'products'
1194
- )
1195
-
1196
- If you need an external CSV export button , add class +wg-external-csv-export-button+
1197
- to any clickable element on page and set its attribute +data-grid-name+ to the name of the grid:
1198
-
1199
- <button class="wg-external-csv-export-button" data-grid-name="grid">Export To CSV</button>
1200
-
1201
- If you need to disable the default export icon in the grid, add <tt>hide_csv_button: true</tt> to the +grid+ helper.
1202
-
1203
-
1204
- == Access to Records From Outside The Grid
1205
-
1206
- There are two ways you can access the records outside the grid - using methods of the WiceGrid
1207
- object and using callbacks.
1208
-
1209
- === Accessing Records Via The WiceGrid Object
1210
-
1211
- Method +current_page_records+ returns exactly the same list of objects displayed on page:
1212
-
1213
- <%= grid(@tasks_grid) do |g|
1214
- ...
1215
- end -%>
1216
-
1217
- <p>
1218
- IDs of records on the current page:
1219
- <%= @tasks_grid.current_page_records.map(&:id).to_sentence %>
1220
- </p>
1221
-
1222
- Method +all_pages_records+ returns a list of objects browsable through all pages with the current filters:
1223
-
1224
- <%= grid(@tasks_grid) do |g|
1225
- ...
1226
- end -%>
1227
-
1228
- <p>
1229
- IDs of all records:
1230
- <%= @tasks_grid.all_pages_records.map(&:id).to_sentence %>
1231
- </p>
1232
-
1233
- Mind that this helper results in an additional SQL query.
1234
-
1235
-
1236
- Because of the current implementation of WiceGrid these helpers work only after the declaration
1237
- of the grid in the view.
1238
- This is due to the lazy nature of WiceGrid - the actual call to the database is made during
1239
- the execution of
1240
- the +grid+ helper, because to build the correct query columns declarations are required.
1241
-
1242
- === Accessing Records Via Callbacks
1243
-
1244
- It is possible to set up callbacks which are executed from within the plugin just after the call to the database.
1245
- The callbacks are called before rendering the grid cells, so the results of this processing can be used in the grid.
1246
- There are 3 ways you can set up such callbacks:
1247
-
1248
- Via a lambda object:
1249
-
1250
- def index
1251
- @tasks_grid = initialize_grid(Task,
1252
- with_paginated_resultset: ->(records){
1253
- ...
1254
- }
1255
- )
1256
- end
1257
-
1258
- Via a symbol which is the name of a controller method:
1259
-
1260
- def index
1261
- @tasks_grid = initialize_grid(Task,
1262
- with_paginated_resultset: :process_selection
1263
- )
1264
- end
1265
-
1266
- def process_selection(records)
1267
- ...
1268
- end
1269
-
1270
- Via a separate block:
1271
-
1272
- def index
1273
- @tasks_grid = initialize_grid(Task)
1274
-
1275
- @tasks_grid.with_paginated_resultset do |records|
1276
- ...
1277
- end
1278
- end
1279
-
1280
- There are two callbacks:
1281
-
1282
- * <tt>:with_paginated_resultset</tt> - used to process records of the current page
1283
- * <tt>:with_resultset</tt> - used to process all records browsable through all pages with the current filters
1284
-
1285
- While the <tt>:with_paginated_resultset</tt> callback just receives the list of records, <tt>:with_resultset</tt>
1286
- receives an ActiveRelation object which can be used to obtain the list of all records:
1287
-
1288
-
1289
- def index
1290
- @tasks_grid = initialize_grid(Task)
1291
-
1292
- @tasks_grid.with_resultset do |active_relation|
1293
- all_records = active_relation.all
1294
- ...
1295
- end
1296
- end
1297
-
1298
-
1299
- This lazy nature exists for performance reasons.
1300
- Reading all records leads to an additional call, and there can be cases when processing all records should be triggered
1301
- only under certain circumstances:
1302
-
1303
- def index
1304
- @tasks_grid = initialize_grid(Task)
1305
-
1306
- @tasks_grid.with_resultset do |active_relation|
1307
- if params[:process_all_records]
1308
- all_records = active_relation.all
1309
- ...
1310
- end
1311
- end
1312
- end
1313
-
1314
-
1315
-
1316
- == Icons
1317
-
1318
- Icons used by the plugin are courtesy of Mark James, the creator of {the SILK icon set}[http://www.famfamfam.com/lab/icons/silk/].
1319
-
1320
- == Bug reports
1321
-
1322
- The author of the plugins welcomes any contribution.
1323
- Please follow {these guidelines}[https://github.com/leikind/wice_grid/wiki/How-to-submit-a-bug-report-or-a-question] when submitting a bug report.
1324
-
1325
-