wice_grid 3.5.0 → 3.6.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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
-