pwice_grid 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (389) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +68 -0
  3. data/.circleci/run-build-locally.sh +7 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
  5. data/.gitignore +22 -0
  6. data/.inch.yml +3 -0
  7. data/.rspec +3 -0
  8. data/.rubocop.yml +186 -0
  9. data/Appraisals +11 -0
  10. data/CHANGELOG.md +758 -0
  11. data/Gemfile +3 -0
  12. data/Gemfile.lock +298 -0
  13. data/MIT-LICENSE +20 -0
  14. data/README.md +1561 -0
  15. data/Rakefile +49 -0
  16. data/SAVED_QUERIES_HOWTO.md +113 -0
  17. data/app/views/kaminari/wice_grid/_gap.html.erb +1 -0
  18. data/app/views/kaminari/wice_grid/_next_page.html.erb +1 -0
  19. data/app/views/kaminari/wice_grid/_page.html.erb +1 -0
  20. data/app/views/kaminari/wice_grid/_paginator.html.erb +19 -0
  21. data/app/views/kaminari/wice_grid/_prev_page.html.erb +1 -0
  22. data/config/locales/cz.yml +40 -0
  23. data/config/locales/de.yml +42 -0
  24. data/config/locales/en.yml +42 -0
  25. data/config/locales/es.yml +42 -0
  26. data/config/locales/fr.yml +40 -0
  27. data/config/locales/is.yml +41 -0
  28. data/config/locales/it.yml +33 -0
  29. data/config/locales/ja.yml +42 -0
  30. data/config/locales/nl.yml +40 -0
  31. data/config/locales/pt-BR.yml +31 -0
  32. data/config/locales/pt.yml +40 -0
  33. data/config/locales/ru.yml +40 -0
  34. data/config/locales/sk.yml +40 -0
  35. data/config/locales/uk.yml +40 -0
  36. data/config/locales/zh.yml +40 -0
  37. data/gemfiles/rails_5.0.gemfile +7 -0
  38. data/gemfiles/rails_5.0.gemfile.lock +299 -0
  39. data/gemfiles/rails_5.1.gemfile +7 -0
  40. data/gemfiles/rails_5.1.gemfile.lock +299 -0
  41. data/gemfiles/rails_5.2.gemfile +7 -0
  42. data/gemfiles/rails_5.2.gemfile.lock +307 -0
  43. data/lib/generators/wice_grid/add_migration_for_serialized_queries_generator.rb +19 -0
  44. data/lib/generators/wice_grid/install_generator.rb +13 -0
  45. data/lib/generators/wice_grid/templates/create_wice_grid_serialized_queries.rb +13 -0
  46. data/lib/generators/wice_grid/templates/wice_grid_config.rb +191 -0
  47. data/lib/wice/active_record_column_wrapper.rb +122 -0
  48. data/lib/wice/columns.rb +282 -0
  49. data/lib/wice/columns/column_action.rb +51 -0
  50. data/lib/wice/columns/column_boolean.rb +39 -0
  51. data/lib/wice/columns/column_bootstrap_datepicker.rb +47 -0
  52. data/lib/wice/columns/column_custom_dropdown.rb +114 -0
  53. data/lib/wice/columns/column_float.rb +8 -0
  54. data/lib/wice/columns/column_html5_datepicker.rb +30 -0
  55. data/lib/wice/columns/column_integer.rb +87 -0
  56. data/lib/wice/columns/column_jquery_datepicker.rb +48 -0
  57. data/lib/wice/columns/column_processor_index.rb +22 -0
  58. data/lib/wice/columns/column_rails_date_helper.rb +40 -0
  59. data/lib/wice/columns/column_rails_datetime_helper.rb +40 -0
  60. data/lib/wice/columns/column_range.rb +73 -0
  61. data/lib/wice/columns/column_string.rb +91 -0
  62. data/lib/wice/columns/common_date_datetime_mixin.rb +19 -0
  63. data/lib/wice/columns/common_js_date_datetime_conditions_generator_mixin.rb +38 -0
  64. data/lib/wice/columns/common_js_date_datetime_mixin.rb +14 -0
  65. data/lib/wice/columns/common_rails_date_datetime_conditions_generator_mixin.rb +25 -0
  66. data/lib/wice/columns/common_standard_helper_date_datetime_mixin.rb +21 -0
  67. data/lib/wice/grid_output_buffer.rb +48 -0
  68. data/lib/wice/grid_renderer.rb +624 -0
  69. data/lib/wice/helpers/bs_calendar_helpers.rb +73 -0
  70. data/lib/wice/helpers/js_calendar_helpers.rb +82 -0
  71. data/lib/wice/helpers/wice_grid_misc_view_helpers.rb +74 -0
  72. data/lib/wice/helpers/wice_grid_serialized_queries_view_helpers.rb +94 -0
  73. data/lib/wice/helpers/wice_grid_view_helpers.rb +719 -0
  74. data/lib/wice/kaminari_monkey_patching.rb +12 -0
  75. data/lib/wice/table_column_matrix.rb +64 -0
  76. data/lib/wice/wice_grid_controller.rb +174 -0
  77. data/lib/wice/wice_grid_core_ext.rb +145 -0
  78. data/lib/wice/wice_grid_misc.rb +208 -0
  79. data/lib/wice/wice_grid_serialized_queries_controller.rb +86 -0
  80. data/lib/wice/wice_grid_serialized_query.rb +13 -0
  81. data/lib/wice/wice_grid_spreadsheet.rb +19 -0
  82. data/lib/wice_grid.rb +702 -0
  83. data/spec/acceptance_helper.rb +59 -0
  84. data/spec/features/action_column_request_spec.rb +280 -0
  85. data/spec/features/adding_rows_request_spec.rb +21 -0
  86. data/spec/features/all_records_request_spec.rb +18 -0
  87. data/spec/features/auto_reloads2_request_spec.rb +366 -0
  88. data/spec/features/auto_reloads3_request_spec.rb +130 -0
  89. data/spec/features/auto_reloads_request_spec.rb +364 -0
  90. data/spec/features/basics1_request_spec.rb +11 -0
  91. data/spec/features/basics2_request_spec.rb +10 -0
  92. data/spec/features/basics3_request_spec.rb +29 -0
  93. data/spec/features/basics4_request_spec.rb +19 -0
  94. data/spec/features/basics5_request_spec.rb +13 -0
  95. data/spec/features/basics6_request_spec.rb +22 -0
  96. data/spec/features/blockless_column_definition_spec.rb +27 -0
  97. data/spec/features/buttons_request_spec.rb +172 -0
  98. data/spec/features/csv_and_detached_filters_spec.rb +10 -0
  99. data/spec/features/csv_export_request_spec.rb +13 -0
  100. data/spec/features/custom_filter_params_request_spec.rb +29 -0
  101. data/spec/features/custom_filters1_request_spec.rb +136 -0
  102. data/spec/features/custom_filters2_request_spec.rb +31 -0
  103. data/spec/features/custom_filters3_request_spec.rb +34 -0
  104. data/spec/features/custom_filters4_request_spec.rb +13 -0
  105. data/spec/features/custom_ordering_on_calculated_request_spec.rb +30 -0
  106. data/spec/features/custom_ordering_request_spec.rb +36 -0
  107. data/spec/features/custom_ordering_with_arel_request_spec.rb +36 -0
  108. data/spec/features/custom_ordering_with_proc_request_spec.rb +44 -0
  109. data/spec/features/custom_ordering_with_ruby_request_spec.rb +30 -0
  110. data/spec/features/dates_request_spec.rb +56 -0
  111. data/spec/features/detached_filters_spec.rb +10 -0
  112. data/spec/features/detached_filters_two_grids_spec.rb +135 -0
  113. data/spec/features/disable_all_filters_spec.rb +22 -0
  114. data/spec/features/hiding_checkboxes_in_action_column_request_spec.rb +294 -0
  115. data/spec/features/integration_with_application_view_request_spec.rb +43 -0
  116. data/spec/features/integration_with_forms_request_spec.rb +141 -0
  117. data/spec/features/joining_tables_spec.rb +40 -0
  118. data/spec/features/localization_request_spec.rb +24 -0
  119. data/spec/features/many_grids_on_page_request_spec.rb +104 -0
  120. data/spec/features/negation_request_spec.rb +25 -0
  121. data/spec/features/no_records_request_spec.rb +26 -0
  122. data/spec/features/numeric_filters_request_spec.rb +10 -0
  123. data/spec/features/resultset_processings2_request_spec.rb +27 -0
  124. data/spec/features/resultset_processings_request_spec.rb +30 -0
  125. data/spec/features/saved_queries_request_spec.rb +120 -0
  126. data/spec/features/shared.rb +1005 -0
  127. data/spec/features/shared_detached_filters.rb +175 -0
  128. data/spec/features/styling_spec.rb +15 -0
  129. data/spec/features/two_associations_spec.rb +48 -0
  130. data/spec/features/upper_pagination_panel_request_spec.rb +23 -0
  131. data/spec/features/when_filtered_spec.rb +209 -0
  132. data/spec/fixtures/.gitkeep +0 -0
  133. data/spec/fixtures/companies.yml +21 -0
  134. data/spec/fixtures/priorities.yml +31 -0
  135. data/spec/fixtures/project_roles.yml +25 -0
  136. data/spec/fixtures/projects.yml +22 -0
  137. data/spec/fixtures/statuses.yml +55 -0
  138. data/spec/fixtures/tasks.yml +751 -0
  139. data/spec/fixtures/tasks_users.yml +2089 -0
  140. data/spec/fixtures/users.yml +61 -0
  141. data/spec/fixtures/versions.yml +78 -0
  142. data/spec/models/company_spec.rb +6 -0
  143. data/spec/models/priority_spec.rb +6 -0
  144. data/spec/models/project_spec.rb +11 -0
  145. data/spec/models/status_spec.rb +6 -0
  146. data/spec/models/task_spec.rb +12 -0
  147. data/spec/models/user_project_participation_spec.rb +7 -0
  148. data/spec/models/user_spec.rb +12 -0
  149. data/spec/models/version_spec.rb +5 -0
  150. data/spec/rails_helper.rb +15 -0
  151. data/spec/schema.rb +8 -0
  152. data/spec/spec_helper.rb +75 -0
  153. data/spec/support/active_record.rb +10 -0
  154. data/spec/support/test_app/Rakefile +3 -0
  155. data/spec/support/test_app/app/assets/javascripts/application.js +20 -0
  156. data/spec/support/test_app/app/assets/javascripts/common.js.coffee +6 -0
  157. data/spec/support/test_app/app/assets/javascripts/jquery.ui.datepicker.locales.js +56 -0
  158. data/spec/support/test_app/app/assets/stylesheets/adding_rows.scss +3 -0
  159. data/spec/support/test_app/app/assets/stylesheets/application.scss +46 -0
  160. data/spec/support/test_app/app/assets/stylesheets/csv_and_detached_filters.scss +3 -0
  161. data/spec/support/test_app/app/assets/stylesheets/many_grids_on_page.scss +3 -0
  162. data/spec/support/test_app/app/controllers/action_column_controller.rb +15 -0
  163. data/spec/support/test_app/app/controllers/adding_rows_controller.rb +14 -0
  164. data/spec/support/test_app/app/controllers/all_records_controller.rb +14 -0
  165. data/spec/support/test_app/app/controllers/application_controller.rb +99 -0
  166. data/spec/support/test_app/app/controllers/auto_reloads2_controller.rb +14 -0
  167. data/spec/support/test_app/app/controllers/auto_reloads3_controller.rb +20 -0
  168. data/spec/support/test_app/app/controllers/auto_reloads_controller.rb +14 -0
  169. data/spec/support/test_app/app/controllers/basics1_controller.rb +6 -0
  170. data/spec/support/test_app/app/controllers/basics2_controller.rb +6 -0
  171. data/spec/support/test_app/app/controllers/basics3_controller.rb +6 -0
  172. data/spec/support/test_app/app/controllers/basics4_controller.rb +6 -0
  173. data/spec/support/test_app/app/controllers/basics5_controller.rb +6 -0
  174. data/spec/support/test_app/app/controllers/basics6_controller.rb +11 -0
  175. data/spec/support/test_app/app/controllers/blockless_column_definition_controller.rb +6 -0
  176. data/spec/support/test_app/app/controllers/buttons_controller.rb +6 -0
  177. data/spec/support/test_app/app/controllers/csv_and_detached_filters_controller.rb +13 -0
  178. data/spec/support/test_app/app/controllers/csv_export_controller.rb +28 -0
  179. data/spec/support/test_app/app/controllers/custom_filter_params_controller.rb +6 -0
  180. data/spec/support/test_app/app/controllers/custom_filters1_controller.rb +9 -0
  181. data/spec/support/test_app/app/controllers/custom_filters2_controller.rb +14 -0
  182. data/spec/support/test_app/app/controllers/custom_filters3_controller.rb +12 -0
  183. data/spec/support/test_app/app/controllers/custom_filters4_controller.rb +12 -0
  184. data/spec/support/test_app/app/controllers/custom_ordering_controller.rb +18 -0
  185. data/spec/support/test_app/app/controllers/custom_ordering_on_calculated_controller.rb +6 -0
  186. data/spec/support/test_app/app/controllers/custom_ordering_with_arel_controller.rb +18 -0
  187. data/spec/support/test_app/app/controllers/custom_ordering_with_proc_controller.rb +11 -0
  188. data/spec/support/test_app/app/controllers/custom_ordering_with_ruby_controller.rb +6 -0
  189. data/spec/support/test_app/app/controllers/dates_controller.rb +8 -0
  190. data/spec/support/test_app/app/controllers/detached_filters_controller.rb +6 -0
  191. data/spec/support/test_app/app/controllers/detached_filters_two_grids_controller.rb +7 -0
  192. data/spec/support/test_app/app/controllers/disable_all_filters_controller.rb +6 -0
  193. data/spec/support/test_app/app/controllers/hiding_checkboxes_in_action_column_controller.rb +13 -0
  194. data/spec/support/test_app/app/controllers/home_controller.rb +3 -0
  195. data/spec/support/test_app/app/controllers/integration_with_application_view_controller.rb +16 -0
  196. data/spec/support/test_app/app/controllers/integration_with_forms_controller.rb +11 -0
  197. data/spec/support/test_app/app/controllers/joining_tables_controller.rb +11 -0
  198. data/spec/support/test_app/app/controllers/localization_controller.rb +26 -0
  199. data/spec/support/test_app/app/controllers/many_grids_on_page_controller.rb +7 -0
  200. data/spec/support/test_app/app/controllers/negation_controller.rb +14 -0
  201. data/spec/support/test_app/app/controllers/no_records_controller.rb +8 -0
  202. data/spec/support/test_app/app/controllers/null_values_controller.rb +10 -0
  203. data/spec/support/test_app/app/controllers/numeric_filters_controller.rb +6 -0
  204. data/spec/support/test_app/app/controllers/queries_controller.rb +4 -0
  205. data/spec/support/test_app/app/controllers/resultset_processings2_controller.rb +29 -0
  206. data/spec/support/test_app/app/controllers/resultset_processings_controller.rb +30 -0
  207. data/spec/support/test_app/app/controllers/saved_queries_controller.rb +14 -0
  208. data/spec/support/test_app/app/controllers/styling_controller.rb +7 -0
  209. data/spec/support/test_app/app/controllers/tasks_controller.rb +14 -0
  210. data/spec/support/test_app/app/controllers/two_associations_controller.rb +6 -0
  211. data/spec/support/test_app/app/controllers/upper_pagination_panel_controller.rb +6 -0
  212. data/spec/support/test_app/app/controllers/when_filtered_controller.rb +6 -0
  213. data/spec/support/test_app/app/helpers/application_helper.rb +82 -0
  214. data/spec/support/test_app/app/mailers/.gitkeep +0 -0
  215. data/spec/support/test_app/app/models/.gitkeep +0 -0
  216. data/spec/support/test_app/app/models/company.rb +5 -0
  217. data/spec/support/test_app/app/models/populate.rb +84 -0
  218. data/spec/support/test_app/app/models/priority.rb +10 -0
  219. data/spec/support/test_app/app/models/project.rb +14 -0
  220. data/spec/support/test_app/app/models/project_role.rb +3 -0
  221. data/spec/support/test_app/app/models/status.rb +10 -0
  222. data/spec/support/test_app/app/models/task.rb +11 -0
  223. data/spec/support/test_app/app/models/to_dropdown_mixin.rb +16 -0
  224. data/spec/support/test_app/app/models/user.rb +8 -0
  225. data/spec/support/test_app/app/models/user_project_participation.rb +6 -0
  226. data/spec/support/test_app/app/models/version.rb +6 -0
  227. data/spec/support/test_app/app/views/action_column/_grid.html.erb +35 -0
  228. data/spec/support/test_app/app/views/action_column/index.html.haml +45 -0
  229. data/spec/support/test_app/app/views/adding_rows/_grid.html.erb +58 -0
  230. data/spec/support/test_app/app/views/adding_rows/index.html.haml +37 -0
  231. data/spec/support/test_app/app/views/all_records/_grid.html.erb +30 -0
  232. data/spec/support/test_app/app/views/all_records/index.html.haml +12 -0
  233. data/spec/support/test_app/app/views/auto_reloads/_grid.html.erb +32 -0
  234. data/spec/support/test_app/app/views/auto_reloads/index.html.haml +15 -0
  235. data/spec/support/test_app/app/views/auto_reloads2/_grid.html.erb +32 -0
  236. data/spec/support/test_app/app/views/auto_reloads2/index.html.haml +65 -0
  237. data/spec/support/test_app/app/views/auto_reloads3/_grid.html.erb +25 -0
  238. data/spec/support/test_app/app/views/auto_reloads3/index.html.haml +78 -0
  239. data/spec/support/test_app/app/views/basics1/_grid.html.erb +26 -0
  240. data/spec/support/test_app/app/views/basics1/index.html.haml +13 -0
  241. data/spec/support/test_app/app/views/basics2/_grid.html.erb +27 -0
  242. data/spec/support/test_app/app/views/basics2/index.html.haml +12 -0
  243. data/spec/support/test_app/app/views/basics3/_grid.html.erb +28 -0
  244. data/spec/support/test_app/app/views/basics3/index.html.haml +13 -0
  245. data/spec/support/test_app/app/views/basics4/_grid.html.erb +21 -0
  246. data/spec/support/test_app/app/views/basics4/index.html.haml +12 -0
  247. data/spec/support/test_app/app/views/basics5/_grid.html.erb +19 -0
  248. data/spec/support/test_app/app/views/basics5/index.html.haml +12 -0
  249. data/spec/support/test_app/app/views/basics6/_grid.html.erb +19 -0
  250. data/spec/support/test_app/app/views/basics6/index.html.haml +23 -0
  251. data/spec/support/test_app/app/views/blockless_column_definition/_grid.html.erb +19 -0
  252. data/spec/support/test_app/app/views/blockless_column_definition/index.html.haml +15 -0
  253. data/spec/support/test_app/app/views/buttons/_grid.html.erb +20 -0
  254. data/spec/support/test_app/app/views/buttons/index.html.haml +30 -0
  255. data/spec/support/test_app/app/views/csv_and_detached_filters/_grid.html.erb +23 -0
  256. data/spec/support/test_app/app/views/csv_and_detached_filters/index.html.haml +58 -0
  257. data/spec/support/test_app/app/views/csv_export/_projects_grid.html.erb +17 -0
  258. data/spec/support/test_app/app/views/csv_export/_tasks_grid.html.erb +43 -0
  259. data/spec/support/test_app/app/views/csv_export/index.html.haml +90 -0
  260. data/spec/support/test_app/app/views/custom_filter_params/_grid.html.erb +12 -0
  261. data/spec/support/test_app/app/views/custom_filter_params/index.html.haml +12 -0
  262. data/spec/support/test_app/app/views/custom_filters1/_g1.html.erb +8 -0
  263. data/spec/support/test_app/app/views/custom_filters1/_g2.html.erb +9 -0
  264. data/spec/support/test_app/app/views/custom_filters1/_g3.html.erb +9 -0
  265. data/spec/support/test_app/app/views/custom_filters1/_g4.html.erb +8 -0
  266. data/spec/support/test_app/app/views/custom_filters1/index.html.haml +30 -0
  267. data/spec/support/test_app/app/views/custom_filters2/_grid.html.erb +30 -0
  268. data/spec/support/test_app/app/views/custom_filters2/index.html.haml +41 -0
  269. data/spec/support/test_app/app/views/custom_filters3/_grid.html.erb +18 -0
  270. data/spec/support/test_app/app/views/custom_filters3/index.html.haml +16 -0
  271. data/spec/support/test_app/app/views/custom_filters4/_grid.html.erb +20 -0
  272. data/spec/support/test_app/app/views/custom_filters4/index.html.haml +12 -0
  273. data/spec/support/test_app/app/views/custom_ordering/_grid.html.erb +10 -0
  274. data/spec/support/test_app/app/views/custom_ordering/index.html.haml +24 -0
  275. data/spec/support/test_app/app/views/custom_ordering_on_calculated/_grid.html.erb +14 -0
  276. data/spec/support/test_app/app/views/custom_ordering_on_calculated/index.html.haml +23 -0
  277. data/spec/support/test_app/app/views/custom_ordering_with_arel/_grid.html.erb +10 -0
  278. data/spec/support/test_app/app/views/custom_ordering_with_arel/index.html.haml +24 -0
  279. data/spec/support/test_app/app/views/custom_ordering_with_proc/_grid.html.erb +10 -0
  280. data/spec/support/test_app/app/views/custom_ordering_with_proc/index.html.haml +21 -0
  281. data/spec/support/test_app/app/views/custom_ordering_with_ruby/_grid.html.erb +10 -0
  282. data/spec/support/test_app/app/views/custom_ordering_with_ruby/index.html.haml +23 -0
  283. data/spec/support/test_app/app/views/dates/_grid.html.erb +25 -0
  284. data/spec/support/test_app/app/views/dates/index.html.haml +52 -0
  285. data/spec/support/test_app/app/views/detached_filters/_grid.html.erb +23 -0
  286. data/spec/support/test_app/app/views/detached_filters/index.html.haml +79 -0
  287. data/spec/support/test_app/app/views/detached_filters_two_grids/_grid.html.erb +23 -0
  288. data/spec/support/test_app/app/views/detached_filters_two_grids/index.html.haml +85 -0
  289. data/spec/support/test_app/app/views/disable_all_filters/_grid.html.erb +21 -0
  290. data/spec/support/test_app/app/views/disable_all_filters/index.html.haml +14 -0
  291. data/spec/support/test_app/app/views/hiding_checkboxes_in_action_column/_grid.html.erb +34 -0
  292. data/spec/support/test_app/app/views/hiding_checkboxes_in_action_column/index.html.haml +32 -0
  293. data/spec/support/test_app/app/views/integration_with_application_view/_grid.html.erb +27 -0
  294. data/spec/support/test_app/app/views/integration_with_application_view/index.html.haml +33 -0
  295. data/spec/support/test_app/app/views/integration_with_forms/_grid.html.erb +23 -0
  296. data/spec/support/test_app/app/views/integration_with_forms/index.html.haml +18 -0
  297. data/spec/support/test_app/app/views/joining_tables/_grid.html.erb +23 -0
  298. data/spec/support/test_app/app/views/joining_tables/index.html.haml +26 -0
  299. data/spec/support/test_app/app/views/layouts/application.html.haml +61 -0
  300. data/spec/support/test_app/app/views/localization/_grid.html.erb +36 -0
  301. data/spec/support/test_app/app/views/localization/index.html.haml +20 -0
  302. data/spec/support/test_app/app/views/many_grids_on_page/_tasks_grid1.html.erb +12 -0
  303. data/spec/support/test_app/app/views/many_grids_on_page/_tasks_grid2.html.erb +12 -0
  304. data/spec/support/test_app/app/views/many_grids_on_page/index.html.haml +26 -0
  305. data/spec/support/test_app/app/views/negation/_grid.html.erb +30 -0
  306. data/spec/support/test_app/app/views/negation/index.html.haml +15 -0
  307. data/spec/support/test_app/app/views/no_records/_empty_grid.html.haml +1 -0
  308. data/spec/support/test_app/app/views/no_records/_grid1.html.erb +11 -0
  309. data/spec/support/test_app/app/views/no_records/_grid2.html.erb +9 -0
  310. data/spec/support/test_app/app/views/no_records/_grid3.html.erb +9 -0
  311. data/spec/support/test_app/app/views/no_records/index.html.haml +24 -0
  312. data/spec/support/test_app/app/views/null_values/_grid.html.erb +17 -0
  313. data/spec/support/test_app/app/views/null_values/index.html.haml +21 -0
  314. data/spec/support/test_app/app/views/numeric_filters/_grid.html.erb +19 -0
  315. data/spec/support/test_app/app/views/numeric_filters/index.html.haml +12 -0
  316. data/spec/support/test_app/app/views/resultset_processings/_grid.html.erb +27 -0
  317. data/spec/support/test_app/app/views/resultset_processings/index.html.haml +50 -0
  318. data/spec/support/test_app/app/views/resultset_processings2/_grid.html.erb +27 -0
  319. data/spec/support/test_app/app/views/resultset_processings2/index.html.haml +48 -0
  320. data/spec/support/test_app/app/views/saved_queries/_grid.html.erb +30 -0
  321. data/spec/support/test_app/app/views/saved_queries/index.html.haml +15 -0
  322. data/spec/support/test_app/app/views/styling/_grid1.html.erb +12 -0
  323. data/spec/support/test_app/app/views/styling/_grid2.html.erb +31 -0
  324. data/spec/support/test_app/app/views/styling/index.html.haml +65 -0
  325. data/spec/support/test_app/app/views/tasks/_grid.html.erb +19 -0
  326. data/spec/support/test_app/app/views/tasks/index.html.haml +1 -0
  327. data/spec/support/test_app/app/views/two_associations/_grid.html.erb +13 -0
  328. data/spec/support/test_app/app/views/two_associations/index.html.haml +13 -0
  329. data/spec/support/test_app/app/views/upper_pagination_panel/_grid.html.erb +27 -0
  330. data/spec/support/test_app/app/views/upper_pagination_panel/index.html.haml +14 -0
  331. data/spec/support/test_app/app/views/when_filtered/_grid.html.erb +19 -0
  332. data/spec/support/test_app/app/views/when_filtered/index.html.haml +15 -0
  333. data/spec/support/test_app/bin/rails +4 -0
  334. data/spec/support/test_app/bin/rake +4 -0
  335. data/spec/support/test_app/config.ru +5 -0
  336. data/spec/support/test_app/config/application.rb +70 -0
  337. data/spec/support/test_app/config/boot.rb +7 -0
  338. data/spec/support/test_app/config/database.travis.yml +27 -0
  339. data/spec/support/test_app/config/database.yml +16 -0
  340. data/spec/support/test_app/config/database.yml.mysql +19 -0
  341. data/spec/support/test_app/config/database.yml.postgresql +18 -0
  342. data/spec/support/test_app/config/environment.rb +6 -0
  343. data/spec/support/test_app/config/environments/development.rb +34 -0
  344. data/spec/support/test_app/config/environments/production.rb +66 -0
  345. data/spec/support/test_app/config/environments/test.rb +34 -0
  346. data/spec/support/test_app/config/initializers/backtrace_silencers.rb +8 -0
  347. data/spec/support/test_app/config/initializers/inflections.rb +16 -0
  348. data/spec/support/test_app/config/initializers/mime_types.rb +6 -0
  349. data/spec/support/test_app/config/initializers/secret_token.rb +12 -0
  350. data/spec/support/test_app/config/initializers/session_store.rb +9 -0
  351. data/spec/support/test_app/config/initializers/wice_grid_config.rb +163 -0
  352. data/spec/support/test_app/config/initializers/wrap_parameters.rb +15 -0
  353. data/spec/support/test_app/config/locales/en.yml +5 -0
  354. data/spec/support/test_app/config/locales/wice_grid.yml +550 -0
  355. data/spec/support/test_app/config/puma.rb +15 -0
  356. data/spec/support/test_app/config/routes.rb +125 -0
  357. data/spec/support/test_app/db/migrate/20120224193505_create_tasks.rb +27 -0
  358. data/spec/support/test_app/db/migrate/20120224193517_create_users.rb +12 -0
  359. data/spec/support/test_app/db/migrate/20120224193522_create_projects.rb +14 -0
  360. data/spec/support/test_app/db/migrate/20120224193529_create_priorities.rb +13 -0
  361. data/spec/support/test_app/db/migrate/20120224193537_create_statuses.rb +13 -0
  362. data/spec/support/test_app/db/migrate/20120224193543_create_versions.rb +15 -0
  363. data/spec/support/test_app/db/migrate/20120224193550_create_project_roles.rb +12 -0
  364. data/spec/support/test_app/db/migrate/20120224193610_create_companies.rb +12 -0
  365. data/spec/support/test_app/db/migrate/20120224195351_create_user_project_participations.rb +16 -0
  366. data/spec/support/test_app/db/migrate/20120224195521_add_tasks_users.rb +11 -0
  367. data/spec/support/test_app/db/migrate/20120610091944_create_wice_grid_serialized_queries.rb +14 -0
  368. data/spec/support/test_app/db/schema.rb +139 -0
  369. data/spec/support/test_app/db/seeds.rb +10 -0
  370. data/spec/support/test_app/lib/ar_fixtures.rb +100 -0
  371. data/spec/support/test_app/lib/assets/.gitkeep +0 -0
  372. data/spec/support/test_app/lib/tasks/.gitkeep +0 -0
  373. data/spec/support/test_app/lib/tasks/ar_fixtures.rake +45 -0
  374. data/spec/support/test_app/public/404.html +26 -0
  375. data/spec/support/test_app/public/422.html +26 -0
  376. data/spec/support/test_app/public/500.html +25 -0
  377. data/spec/support/test_app/public/favicon.ico +0 -0
  378. data/spec/support/test_app/public/robots.txt +5 -0
  379. data/spec/wice/grid_output_buffer_spec.rb +39 -0
  380. data/spec/wice/table_column_matrix_spec.rb +36 -0
  381. data/spec/wice/wice_grid_misc_spec.rb +157 -0
  382. data/spec/wice/wice_grid_spreadsheet_spec.rb +12 -0
  383. data/vendor/assets/javascripts/wice_grid.js +3 -0
  384. data/vendor/assets/javascripts/wice_grid_init.js.coffee +351 -0
  385. data/vendor/assets/javascripts/wice_grid_processor.js.coffee +133 -0
  386. data/vendor/assets/javascripts/wice_grid_saved_queries_init.js.coffee +104 -0
  387. data/vendor/assets/stylesheets/wice_grid.scss +81 -0
  388. data/wice_grid.gemspec +54 -0
  389. metadata +861 -0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,298 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ wice_grid (4.1.0)
5
+ coffee-rails (> 3.2)
6
+ kaminari (~> 1.1)
7
+ rails (>= 5.0, < 7)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actioncable (5.1.4)
13
+ actionpack (= 5.1.4)
14
+ nio4r (~> 2.0)
15
+ websocket-driver (~> 0.6.1)
16
+ actionmailer (5.1.4)
17
+ actionpack (= 5.1.4)
18
+ actionview (= 5.1.4)
19
+ activejob (= 5.1.4)
20
+ mail (~> 2.5, >= 2.5.4)
21
+ rails-dom-testing (~> 2.0)
22
+ actionpack (5.1.4)
23
+ actionview (= 5.1.4)
24
+ activesupport (= 5.1.4)
25
+ rack (~> 2.0)
26
+ rack-test (>= 0.6.3)
27
+ rails-dom-testing (~> 2.0)
28
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
29
+ actionview (5.1.4)
30
+ activesupport (= 5.1.4)
31
+ builder (~> 3.1)
32
+ erubi (~> 1.4)
33
+ rails-dom-testing (~> 2.0)
34
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
35
+ activejob (5.1.4)
36
+ activesupport (= 5.1.4)
37
+ globalid (>= 0.3.6)
38
+ activemodel (5.1.4)
39
+ activesupport (= 5.1.4)
40
+ activerecord (5.1.4)
41
+ activemodel (= 5.1.4)
42
+ activesupport (= 5.1.4)
43
+ arel (~> 8.0)
44
+ activesupport (5.1.4)
45
+ concurrent-ruby (~> 1.0, >= 1.0.2)
46
+ i18n (~> 0.7)
47
+ minitest (~> 5.1)
48
+ tzinfo (~> 1.1)
49
+ addressable (2.5.2)
50
+ public_suffix (>= 2.0.2, < 4.0)
51
+ appraisal (2.2.0)
52
+ bundler
53
+ rake
54
+ thor (>= 0.14.0)
55
+ arel (8.0.0)
56
+ bootstrap-sass (3.1.1.1)
57
+ sass (~> 3.2)
58
+ builder (3.2.3)
59
+ byebug (10.0.2)
60
+ capybara (3.13.2)
61
+ addressable
62
+ mini_mime (>= 0.1.3)
63
+ nokogiri (~> 1.8)
64
+ rack (>= 1.6.0)
65
+ rack-test (>= 0.6.3)
66
+ regexp_parser (~> 1.2)
67
+ xpath (~> 3.2)
68
+ capybara-screenshot (1.0.21)
69
+ capybara (>= 1.0, < 4)
70
+ launchy
71
+ childprocess (0.9.0)
72
+ ffi (~> 1.0, >= 1.0.11)
73
+ cliver (0.3.2)
74
+ coderay (1.1.2)
75
+ coffee-rails (4.2.2)
76
+ coffee-script (>= 2.2.0)
77
+ railties (>= 4.0.0)
78
+ coffee-script (2.4.1)
79
+ coffee-script-source
80
+ execjs
81
+ coffee-script-source (1.12.2)
82
+ concurrent-ruby (1.0.5)
83
+ crass (1.0.3)
84
+ diff-lcs (1.3)
85
+ docile (1.1.5)
86
+ erubi (1.7.0)
87
+ execjs (2.7.0)
88
+ faker (1.8.7)
89
+ i18n (>= 0.7)
90
+ ffi (1.9.23)
91
+ font-awesome-sass (4.4.0)
92
+ sass (>= 3.2)
93
+ globalid (0.4.2)
94
+ activesupport (>= 4.2.0)
95
+ haml (5.0.4)
96
+ temple (>= 0.8.0)
97
+ tilt
98
+ httparty (0.16.2)
99
+ multi_xml (>= 0.5.2)
100
+ i18n (0.9.1)
101
+ concurrent-ruby (~> 1.0)
102
+ inch (0.6.4)
103
+ pry
104
+ sparkr (>= 0.2.0)
105
+ term-ansicolor
106
+ yard (~> 0.8.7.5)
107
+ jquery-rails (4.3.3)
108
+ rails-dom-testing (>= 1, < 3)
109
+ railties (>= 4.2.0)
110
+ thor (>= 0.14, < 2.0)
111
+ jquery-ui-rails (5.0.5)
112
+ railties (>= 3.2.16)
113
+ jquery-ui-themes (0.0.12)
114
+ httparty
115
+ json (1.8.6)
116
+ kaminari (1.1.1)
117
+ activesupport (>= 4.1.0)
118
+ kaminari-actionview (= 1.1.1)
119
+ kaminari-activerecord (= 1.1.1)
120
+ kaminari-core (= 1.1.1)
121
+ kaminari-actionview (1.1.1)
122
+ actionview
123
+ kaminari-core (= 1.1.1)
124
+ kaminari-activerecord (1.1.1)
125
+ activerecord
126
+ kaminari-core (= 1.1.1)
127
+ kaminari-core (1.1.1)
128
+ launchy (2.4.3)
129
+ addressable (~> 2.3)
130
+ libv8 (3.16.14.19)
131
+ loofah (2.1.1)
132
+ crass (~> 1.0.2)
133
+ nokogiri (>= 1.5.9)
134
+ mail (2.7.1)
135
+ mini_mime (>= 0.1.1)
136
+ method_source (0.9.0)
137
+ mini_mime (1.0.1)
138
+ mini_portile2 (2.4.0)
139
+ minitest (5.11.1)
140
+ multi_json (1.13.1)
141
+ multi_xml (0.6.0)
142
+ nio4r (2.5.2)
143
+ nokogiri (1.10.1)
144
+ mini_portile2 (~> 2.4.0)
145
+ poltergeist (1.18.1)
146
+ capybara (>= 2.1, < 4)
147
+ cliver (~> 0.3.1)
148
+ websocket-driver (>= 0.2.0)
149
+ pry (0.11.3)
150
+ coderay (~> 1.1.0)
151
+ method_source (~> 0.9.0)
152
+ public_suffix (3.0.2)
153
+ rack (2.0.6)
154
+ rack-test (1.1.0)
155
+ rack (>= 1.0, < 3)
156
+ rails (5.1.4)
157
+ actioncable (= 5.1.4)
158
+ actionmailer (= 5.1.4)
159
+ actionpack (= 5.1.4)
160
+ actionview (= 5.1.4)
161
+ activejob (= 5.1.4)
162
+ activemodel (= 5.1.4)
163
+ activerecord (= 5.1.4)
164
+ activesupport (= 5.1.4)
165
+ bundler (>= 1.3.0)
166
+ railties (= 5.1.4)
167
+ sprockets-rails (>= 2.0.0)
168
+ rails-dom-testing (2.0.3)
169
+ activesupport (>= 4.2.0)
170
+ nokogiri (>= 1.6)
171
+ rails-html-sanitizer (1.0.3)
172
+ loofah (~> 2.0)
173
+ railties (5.1.4)
174
+ actionpack (= 5.1.4)
175
+ activesupport (= 5.1.4)
176
+ method_source
177
+ rake (>= 0.8.7)
178
+ thor (>= 0.18.1, < 2.0)
179
+ rake (10.5.0)
180
+ rb-fsevent (0.10.3)
181
+ rb-inotify (0.9.10)
182
+ ffi (>= 0.5.0, < 2)
183
+ rdoc (4.2.2)
184
+ json (~> 1.4)
185
+ ref (2.0.0)
186
+ regexp_parser (1.3.0)
187
+ rspec (3.6.0)
188
+ rspec-core (~> 3.6.0)
189
+ rspec-expectations (~> 3.6.0)
190
+ rspec-mocks (~> 3.6.0)
191
+ rspec-core (3.6.0)
192
+ rspec-support (~> 3.6.0)
193
+ rspec-expectations (3.6.0)
194
+ diff-lcs (>= 1.2.0, < 2.0)
195
+ rspec-support (~> 3.6.0)
196
+ rspec-mocks (3.6.0)
197
+ diff-lcs (>= 1.2.0, < 2.0)
198
+ rspec-support (~> 3.6.0)
199
+ rspec-rails (3.6.1)
200
+ actionpack (>= 3.0)
201
+ activesupport (>= 3.0)
202
+ railties (>= 3.0)
203
+ rspec-core (~> 3.6.0)
204
+ rspec-expectations (~> 3.6.0)
205
+ rspec-mocks (~> 3.6.0)
206
+ rspec-support (~> 3.6.0)
207
+ rspec-support (3.6.0)
208
+ rubyzip (1.2.1)
209
+ sass (3.5.6)
210
+ sass-listen (~> 4.0.0)
211
+ sass-listen (4.0.0)
212
+ rb-fsevent (~> 0.9, >= 0.9.4)
213
+ rb-inotify (~> 0.9, >= 0.9.7)
214
+ sass-rails (5.0.7)
215
+ railties (>= 4.0.0, < 6)
216
+ sass (~> 3.1)
217
+ sprockets (>= 2.8, < 4.0)
218
+ sprockets-rails (>= 2.0, < 4.0)
219
+ tilt (>= 1.1, < 3)
220
+ selenium-webdriver (2.51.0)
221
+ childprocess (~> 0.5)
222
+ multi_json (~> 1.0)
223
+ rubyzip (~> 1.0)
224
+ websocket (~> 1.0)
225
+ shoulda-matchers (2.8.0)
226
+ activesupport (>= 3.0.0)
227
+ simplecov (0.14.1)
228
+ docile (~> 1.1.0)
229
+ json (>= 1.8, < 3)
230
+ simplecov-html (~> 0.10.0)
231
+ simplecov-html (0.10.2)
232
+ sparkr (0.4.1)
233
+ sprockets (3.7.1)
234
+ concurrent-ruby (~> 1.0)
235
+ rack (> 1, < 3)
236
+ sprockets-rails (3.2.1)
237
+ actionpack (>= 4.0)
238
+ activesupport (>= 4.0)
239
+ sprockets (>= 3.0.0)
240
+ sqlite3 (1.3.13)
241
+ temple (0.8.0)
242
+ term-ansicolor (1.6.0)
243
+ tins (~> 1.0)
244
+ therubyracer (0.12.3)
245
+ libv8 (~> 3.16.14.15)
246
+ ref
247
+ thor (0.19.4)
248
+ thread_safe (0.3.6)
249
+ tilt (2.0.8)
250
+ tins (1.16.3)
251
+ turbolinks (5.1.1)
252
+ turbolinks-source (~> 5.1)
253
+ turbolinks-source (5.1.0)
254
+ tzinfo (1.2.4)
255
+ thread_safe (~> 0.1)
256
+ websocket (1.2.5)
257
+ websocket-driver (0.6.5)
258
+ websocket-extensions (>= 0.1.0)
259
+ websocket-extensions (0.1.3)
260
+ xpath (3.2.0)
261
+ nokogiri (~> 1.8)
262
+ yard (0.8.7.6)
263
+
264
+ PLATFORMS
265
+ ruby
266
+
267
+ DEPENDENCIES
268
+ appraisal
269
+ bootstrap-sass (= 3.1.1.1)
270
+ bundler (~> 1.3)
271
+ byebug
272
+ capybara (~> 3.13.2)
273
+ capybara-screenshot (~> 1.0.11)
274
+ coderay (~> 1.1.0)
275
+ faker (~> 1.8.7)
276
+ font-awesome-sass (= 4.4.0)
277
+ haml (~> 5.0.4)
278
+ inch (~> 0.6.4)
279
+ jquery-rails (~> 4.3.3)
280
+ jquery-ui-rails (~> 5.0.5)
281
+ jquery-ui-themes (~> 0.0.11)
282
+ poltergeist (~> 1.18.0)
283
+ rake (~> 10.1)
284
+ rdoc (~> 4.2.0)
285
+ rspec (~> 3.6.0)
286
+ rspec-rails (~> 3.6.0)
287
+ sass-rails (>= 3.2)
288
+ selenium-webdriver (~> 2.51.0)
289
+ shoulda-matchers (= 2.8.0)
290
+ simplecov (~> 0.7)
291
+ sqlite3 (~> 1.3)
292
+ therubyracer
293
+ turbolinks (~> 5.1.1)
294
+ wice_grid!
295
+ yard (~> 0.8)
296
+
297
+ BUNDLED WITH
298
+ 1.17.2
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008-2014 Yuri Leikind
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,1561 @@
1
+ [![Version](http://img.shields.io/gem/v/wice_grid.svg)](https://rubygems.org/gems/wice_grid)
2
+ [![CircleCI](https://circleci.com/gh/patricklindsay/wice_grid.svg?style=svg)](https://circleci.com/gh/patricklindsay/wice_grid)
3
+ [![Inline docs](http://inch-ci.org/github/patricklindsay/wice_grid.svg)](http://inch-ci.org/github/patricklindsay/wice_grid)
4
+ [![License](http://img.shields.io/badge/license-MIT-yellowgreen.svg)](#license)
5
+
6
+ # WiceGrid
7
+
8
+ THE PROJECT IS LOOKING FOR CONTRIBUTORS.
9
+
10
+ Check out this [sample application](http://wicegrid.herokuapp.com) which demos all features & includes code samples.
11
+
12
+ - [Intro](#intro)
13
+ - [Requirements and Rails versions](#requirements-and-rails-versions)
14
+ - [Installation](#installation)
15
+ - [Basics](#basics)
16
+ - [Rendering filter panel](#rendering-filter-panel)
17
+ - [Initial Ordering](#initial-ordering)
18
+ - [Records Per Page](#records-per-page)
19
+ - [Conditions](#conditions)
20
+ - [Queries with join tables](#queries-with-join-tables)
21
+ - [Joined associations referring to the same table](#joined-associations-referring-to-the-same-table)
22
+ - [More than one grid on a page](#more-than-one_grid-on-a-page)
23
+ - [Custom Ordering](#custom-ordering)
24
+ - [Custom Sorting](#custom-sorting)
25
+ - [Filters](#filters)
26
+ - [Custom dropdown filters](#custom-dropdown-filters)
27
+ - [Numeric Filters](#numeric-filters)
28
+ - [Date and DateTime Filters](#date-and-datetime-filters)
29
+ - [Detached Filters](#detached-filters)
30
+ - [Defaults](#defaults)
31
+ - [Testing](#testing)
32
+ - [Bug reports](#bug-reports)
33
+
34
+
35
+ ## Intro
36
+
37
+ WiceGrid is a Rails grid plugin.
38
+
39
+ One of the goals of this plugin was to allow the programmer to define the contents of the cell on their
40
+ own, just like one does when rendering a collection via a simple table (and this is what differentiates
41
+ WiceGrid from various scaffolding solutions), but automate implementation of filters, ordering,
42
+ paginations, CSV export, and so on. Ruby blocks provide an elegant means for this.
43
+
44
+
45
+ WiceGrid builds the call to the ActiveRecord layer for you and creates a table view with the results
46
+ of the call including:
47
+
48
+ * Pagination
49
+ * Sortable columns
50
+ * Filtering by multiple columns
51
+ * Export to CSV
52
+ * Saved queries
53
+
54
+ Filters are added automatically according to the type of the underlying DB column. Filtering by more
55
+ than one column at the same time is possible. More than one such grid can appear on a page, and
56
+ manipulations with one grid do not have any impact on others.
57
+
58
+ WiceGrid does not take a collection as an input, it works directly with ActiveRecord.
59
+
60
+ WiceGrid does not use XHR calls to reload itself, instead simple GET requests are used for this,
61
+ nevertheless, all other page parameters are respected and preserved. WiceGrid works well with Turbolinks.
62
+
63
+ WiceGrid views do not contain forms so you can include it in your own forms.
64
+
65
+ WiceGrid is known to work with MySQL, Postgres, and Oracle.
66
+
67
+ Continue reading for more information or check out our [CHANGELOG](https://github.com/patricklindsay/wice_grid/blob/master/CHANGELOG.md) to find out whats been going on.
68
+
69
+
70
+ ## Requirements and Rails versions
71
+
72
+ ```
73
+ # Rails => 5
74
+ gem 'wice_grid'
75
+
76
+ # Rails 4
77
+ gem 'wice_grid', '3.6.2'
78
+ ```
79
+
80
+ WiceGrid relies on jQuery.
81
+
82
+ If you need a JS Datepicker, WiceGrid supports jQuery Datepicker or
83
+ [Bootstrap Datepicker](https://github.com/Nerian/bootstrap-datepicker-rails), so you might need one of
84
+ those. See section Installation for details on how to use datepickers.
85
+
86
+ WARNING: Since 3.2.pre2 WiceGrid is not compatible with `will_paginate` because internally it uses
87
+ `kaminari` for pagination, and `kaminari` is not compatible with `will_paginate`!
88
+
89
+
90
+ ## Installation
91
+
92
+ Add the following to your Gemfile & run `bundle`:
93
+
94
+ ```ruby
95
+ gem "wice_grid"
96
+ gem 'font-awesome-sass', '~> 4.3'
97
+ ```
98
+
99
+ Note: `font-awesome-sass` is not a dependency of WiceGrid in case you decide to style WiceGrid icons differently.
100
+
101
+ Run the generator:
102
+
103
+ ```
104
+ rails g wice_grid:install
105
+ ```
106
+
107
+ This adds the following file:
108
+ * `config/initializers/wice_grid_config.rb`
109
+
110
+
111
+ Require WiceGrid javascript in your js index file:
112
+
113
+ ```
114
+ //= require wice_grid
115
+ ```
116
+
117
+ Make sure jQuery is loaded. If the application uses Date and DateTime filters, you have to install
118
+ jQuery Datepicker by yourself. You can also use
119
+ [Bootstrap Datepicker](https://github.com/Nerian/bootstrap-datepicker-rails).
120
+
121
+ Here is an example of `application.js` if jquery.ui.datepicker is used:
122
+
123
+ ```
124
+ //= require jquery
125
+ //= require jquery_ujs
126
+ //= require jquery-ui
127
+ //= require wice_grid
128
+ //= require jquery.ui.datepicker
129
+ //= require_tree .
130
+ ```
131
+
132
+ Here is `application.js` if [Bootstrap Datepicker](https://github.com/Nerian/bootstrap-datepicker-rails) is used:
133
+
134
+ ```
135
+ //= require jquery
136
+ //= require jquery_ujs
137
+ //= require jquery-ui
138
+ //= require wice_grid
139
+ //= require bootstrap-datepicker
140
+ //= require_tree .
141
+ ```
142
+
143
+ Require WiceGrid and [Font Awesome](http://fortawesome.github.io/Font-Awesome/) CSS in your `application.scss`:
144
+
145
+ ```
146
+ @import "wice_grid";
147
+ @import "font-awesome-sprockets";
148
+ @import "font-awesome";
149
+ ```
150
+
151
+ This will provide very basic styles, not specifying exactly how the table should look like, but if
152
+ the application uses Twitter Bootstrap, the markup generated by WiceGrid will have correct classes and
153
+ will fit nicely.
154
+
155
+ WiceGrid uses icons from [Font Awesome](http://fortawesome.github.io/Font-Awesome/).
156
+
157
+ Should you decide to write you own styles for WiceGrid, you can just remove these imports and write your own styles.
158
+
159
+
160
+ ## Basics
161
+
162
+ The simplest example of a WiceGrid for one simple DB table is the following:
163
+
164
+ Controller:
165
+
166
+ ```ruby
167
+ @tasks_grid = initialize_grid(Task)
168
+ ```
169
+
170
+ It is also possible to use an `ActiveRecord::Relation` instance as the first argument:
171
+
172
+ ```ruby
173
+ @tasks_grid = initialize_grid(Task.where(active: true))
174
+ ```
175
+
176
+ View:
177
+
178
+ ```erb
179
+ <%= grid(@tasks_grid) do |g|
180
+
181
+ g.column do |task|
182
+ task.id
183
+ end
184
+
185
+ g.column do |task|
186
+ task.title
187
+ end
188
+
189
+ g.column do |task|
190
+ task.description
191
+ end
192
+
193
+ g.column do |task|
194
+ task.archived? ? 'Yes' : 'No'
195
+ end
196
+
197
+ g.column do |task|
198
+ link_to('Edit', edit_task_path(task))
199
+ end
200
+ end -%>
201
+ ```
202
+
203
+ Code `g.column do |task| ... end`
204
+ defines everything related to a column in the resulting view table including column names, sorting,
205
+ filtering, the content of the column cells, etc. The return value of the block is the table cell content.
206
+
207
+ Column names are defined with parameter `:name`:
208
+
209
+ ```erb
210
+ <%= grid(@tasks_grid) do |g|
211
+
212
+ g.column name: 'ID' do |task|
213
+ task.id
214
+ end
215
+
216
+ g.column name: 'Title' do |task|
217
+ task.title
218
+ end
219
+
220
+ g.column name: 'Description' do |task|
221
+ task.description
222
+ end
223
+
224
+ g.column name: 'Archived' do |task|
225
+ task.archived? ? 'Yes' : 'No'
226
+ end
227
+
228
+ g.column do |task|
229
+ link_to('Edit', edit_task_path(task))
230
+ end
231
+ end -%>
232
+ ```
233
+
234
+ To add filtering and ordering, declare to which column in the underlying database table(s) the view
235
+ column corresponds using parameter `:attribute`:
236
+
237
+ ```erb
238
+ <%= grid(@tasks_grid) do |g|
239
+
240
+ g.column name: 'ID', attribute: 'id' do |task|
241
+ task.id
242
+ end
243
+
244
+ g.column name: 'Title', attribute: 'title' do |task|
245
+ task.title
246
+ end
247
+
248
+ g.column name: 'Description', attribute: 'description' do |task|
249
+ task.description
250
+ end
251
+
252
+ g.column name: 'Archived', attribute: 'archived' do |task|
253
+ task.archived? ? 'Yes' : 'No'
254
+ end
255
+
256
+ g.column do |task|
257
+ link_to('Edit', edit_task_path(task))
258
+ end
259
+ end -%>
260
+ ```
261
+
262
+ This will add sorting links and filters for columns `Username` and `Active`. The plugin automatically
263
+ creates filters according to the type of the database column. In the above example a text field will be
264
+ created for column Title (title is a string), for column `Archived` a dropdown filter will be created
265
+ with options 'Yes', 'No', and '--', and for the integer ID two short text fields are added which can
266
+ contain the numeric range (more than, less than).
267
+
268
+ It is important to remember that `:attribute` is the name of the database column, not a model attribute.
269
+ Of course, all database columns have corresponding model attributes, but not all model attributes map to
270
+ columns in the same table with the same name.
271
+
272
+ Read more about available filters in the documentation for the column method.
273
+
274
+ Read the section about custom dropdown filters for more advanced filters.
275
+
276
+ For columns like
277
+
278
+ ```ruby
279
+ g.column name: 'Title', attribute: 'title' do |task|
280
+ task.title
281
+ end
282
+ ```
283
+
284
+ where the block contains just a call to the same attribute declared by :attribute, the block can be
285
+ omitted:
286
+
287
+ ```erb
288
+ <%= grid(@tasks_grid) do |g|
289
+
290
+ g.column name: 'ID', attribute: 'id'
291
+
292
+ g.column name: 'Title', attribute: 'title'
293
+
294
+ g.column name: 'Description', attribute: 'description'
295
+
296
+ g.column name: 'Archived', attribute: 'archived' do |task|
297
+ task.archived? ? 'Yes' : 'No'
298
+ end
299
+
300
+ g.column do |task|
301
+ link_to('Edit', edit_task_path(task))
302
+ end
303
+ end -%>
304
+ ```
305
+
306
+ In this case `name` will be used as the method name to send to the ActiveRecord instance.
307
+
308
+ If only ordering is needed, and no filter, we can turn off filters using `:filter` :
309
+
310
+ ```ruby
311
+ g.column name: 'ID', attribute: 'id', filter: false
312
+ ```
313
+
314
+ If no ordering links are needed, use `ordering: false`:
315
+
316
+ ```ruby
317
+ g.column name: 'Added', attribute: 'created_at', ordering: false
318
+ ```
319
+
320
+ It is important to understand that it is up to the developer to make sure that the value returned by a
321
+ column block (the content of a cell) corresponds to the underlying database column specified by
322
+ `:attribute` (and `:assoc` discussed below).
323
+
324
+
325
+ ### Rendering filter panel
326
+
327
+ The filter panel can be shown and hidden clicking the icon with binoculars.
328
+
329
+ The way the filter panel is shown after the page is loaded is controlled via parameter
330
+ `:show_filters` of the `grid` helper.
331
+ Possible values are:
332
+
333
+ * `:when_filtered` - the filter is shown when the current table is the result of filtering
334
+ * `:always` - always show the filter
335
+ * `:no` - never show the filter
336
+
337
+ Example:
338
+
339
+ ```erb
340
+ <%= grid(@tasks_grid, show_filters: :always) do |g|
341
+ ......
342
+ end -%>
343
+ ```
344
+
345
+ Filter related icons (filter icon, reset icon, show/hide icon) are placed in the header of the last
346
+ column if it doesn't have any filter or a column name, otherwise an additional table column is added.
347
+ To always place the icons in the additional column, set
348
+ `Wice::Defaults::REUSE_LAST_COLUMN_FOR_FILTER_ICONS` to `false` in the configuration file.
349
+
350
+
351
+ ### Initial ordering
352
+
353
+ Initializing the grid we can also define the column by which the record will be ordered <em>on the first
354
+ rendering of the grid</em>, when the user has not set their ordering setting by clicking the column label,
355
+ and the order direction:
356
+
357
+ ```ruby
358
+ @tasks_grid = initialize_grid(Task,
359
+ order: 'tasks.title',
360
+ order_direction: 'desc'
361
+ )
362
+ ```
363
+
364
+ ### Records per page
365
+
366
+ The number of rows per page is set with `:per_page`:
367
+
368
+ ```ruby
369
+ @tasks_grid = initialize_grid(Task, per_page: 40)
370
+ ```
371
+
372
+ ### Conditions
373
+
374
+ The `initialize_grid` method supports a `:conditions` parameter which is passed on to the underlying
375
+ ActiveRecord, so it can be in any format processable by ActiveRecord:
376
+
377
+ ```ruby
378
+ @tasks_grid = initialize_grid(Task,
379
+ conditions: ["archived = false and estimated_time > ?", 100]
380
+ )
381
+
382
+ @tasks_grid = initialize_grid(Task,
383
+ include: :project,
384
+ conditions: {archived: false, project: {active: true}}
385
+ )
386
+ ```
387
+
388
+ A good example is substituting a common pattern like
389
+
390
+ ```ruby
391
+ @user_groups = @portal_application.user_groups
392
+ ```
393
+
394
+ with WiceGrid code:
395
+
396
+ ```ruby
397
+ @user_groups_grid = initialize_grid(
398
+ UserGroup,
399
+ conditions: ['portal_application_id = ?', @portal_application]
400
+ )
401
+ ```
402
+
403
+ Alternatively, instead of a Class object as the first parameter, you can use ActiveRecord::Relation:
404
+
405
+ ```ruby
406
+ @tasks_grid = initialize_grid(
407
+ Task.where(archived: false, projects: {active: true}).joins(:project)
408
+ )
409
+ ```
410
+
411
+ Please note that though all queries inside of WiceGrid are run without the default scope, if you use an
412
+ ActiveRecord::Relation instance to initialize grid, it will already include the default scope. Thus you
413
+ might consider using `unscoped`:
414
+
415
+ ```ruby
416
+ @tasks_grid = initialize_grid(
417
+ Task.unscoped.where(archived: false, projects: {active: true}).joins(:project)
418
+ )
419
+ ```
420
+
421
+ ### Queries with join tables
422
+
423
+ To join other tables, use `:include`:
424
+
425
+ ```ruby
426
+ @products_grid = initialize_grid(Product,
427
+ include: :category,
428
+ order: 'products.name',
429
+ per_page: 20
430
+ )
431
+ ```
432
+
433
+ The value of `:include` can be an array of association names:
434
+
435
+ ```ruby
436
+ include: [:category, :users, :status]
437
+ ```
438
+
439
+ If you need to join tables to joined tables, use hashes:
440
+
441
+
442
+ ```ruby
443
+ include: [:category, {users: :group}, :status]
444
+ ```
445
+
446
+
447
+ Note that if we want to order initially by a column from a joined table we have to specify the table and
448
+ the column name with the sql dot notation, that is, `products.name`.
449
+
450
+ To show columns of joined tables in the view table, specify the corresponding association with `:assoc`:
451
+
452
+ ```erb
453
+ <%= grid(@products_grid) do |g|
454
+ g.column name: 'Product Name', attribute: 'name' do |product| # primary table
455
+ link_to(product.name, product_path(product))
456
+ end
457
+
458
+ g.column name: 'Category', attribute: 'name', assoc: :category do |product| # joined table
459
+ product.category.name
460
+ end
461
+ %>
462
+ ```
463
+
464
+ Please note that the blockless definition of the column can also be used with joined tables:
465
+
466
+ ```
467
+ g.column name: 'Category', attribute: 'name', assoc: :category
468
+
469
+ ```
470
+
471
+ If an association is mentioned in the column definition, it can be omitted from `:include` in `initialize_grid`.
472
+ Thus, the above example can be rewritten without `:category` in `:include`:
473
+
474
+
475
+ ```ruby
476
+ @products_grid = initialize_grid(Product,
477
+ order: 'products.name',
478
+ per_page: 20
479
+ )
480
+ ```
481
+
482
+ ```erb
483
+ <%= grid(@products_grid) do |g|
484
+ g.column name: 'Product Name', attribute: 'name' do |product| # primary table
485
+ link_to(product.name, product_path(product))
486
+ end
487
+
488
+ g.column name: 'Category', attribute: 'name', assoc: :category
489
+
490
+ %>
491
+ ```
492
+
493
+ ### Joined associations referring to the same table
494
+
495
+ In case there are two joined associations both referring to the same table, ActiveRecord constructs a query
496
+ where the second join provides an alias for the joined table. To enable WiceGrid to order and filter by
497
+ columns belonging to different associations but originating from the same table, set `:table_alias`
498
+ to this alias:
499
+
500
+ Model:
501
+
502
+ ```ruby
503
+ class Project < ActiveRecord::Base
504
+ belongs_to :customer, class_name: 'Company'
505
+ belongs_to :supplier, class_name: 'Company'
506
+ end
507
+ ```
508
+
509
+ Controller:
510
+
511
+ ```ruby
512
+ @projects_grid = initialize_grid(Project)
513
+ ```
514
+
515
+ View:
516
+
517
+ ```erb
518
+ <%= grid(@projects_grid, show_filters: :always) do |g|
519
+
520
+ g.column name: 'Project Name', attribute: 'name'
521
+
522
+ g.column name: 'Customer company', assoc: :customer, attribute: 'name'
523
+
524
+ g.column name: 'Supplier company', assoc: :supplier, attribute: 'name', table_alias: 'suppliers_projects'
525
+
526
+ end -%>
527
+ ```
528
+
529
+ ### More than one grid on a page
530
+
531
+ It is possible to use more that one grid on a page, each with its own state. To do so, you must specify the
532
+ name of the grid in `initialize_grid` using parameter `:name`.
533
+
534
+ The name serves as the base name for HTTP parameters, DOM IDs, etc, so it is important that all grids on a
535
+ page have different names. The default name is 'grid'.
536
+
537
+ The name can only contain alphanumeric characters.
538
+
539
+ ```ruby
540
+ @projects_grid = initialize_grid(Project, name: 'g1')
541
+ @tasks_grid = initialize_grid(Task, name: 'g2')
542
+ ```
543
+
544
+ ### Custom Ordering
545
+
546
+ It is possible to change the way results are ordered injecting a chunk of SQL code, for example, use
547
+ `ORDER BY INET_ATON(ip_address)` instead of `ORDER BY ip_address`.
548
+
549
+ To do so, provide parameter `:custom_order` in the initialization of the grid with a `Hash` where
550
+ keys are fully qualified names of database columns, and values are anything that can be passed to ActiveRecord's
551
+ `order` method (without specifying `ASC` or `DESC`.)
552
+
553
+ #### String
554
+
555
+ Starting in Rails 5.2, you may need to whitelist `String` values with `Arel.sql`
556
+ to avoid a warning or error.
557
+
558
+ ```ruby
559
+ @hosts_grid = initialize_grid(Host,
560
+ custom_order: {
561
+ 'hosts.ip_address' => Arel.sql('INET_ATON(hosts.ip_address)')
562
+ })
563
+ ```
564
+
565
+ It is possible to use `?` instead of the name of the column in the `Hash` value:
566
+
567
+ ```ruby
568
+ @hosts_grid = initialize_grid(Host,
569
+ custom_order: {
570
+ 'hosts.ip_address' => Arel.sql('INET_ATON( ? )')
571
+ })
572
+ ```
573
+
574
+ #### Arel::Attributes::Attribute
575
+
576
+ Assuming you wish to display `hosts.ip_address` but sort by another column named `hosts.ip_address_number`:
577
+
578
+ ```ruby
579
+ @hosts_grid = initialize_grid(Host,
580
+ custom_order: {
581
+ 'hosts.ip_address' => Arel::Table.new(:hosts)[:ip_address_number]
582
+ })
583
+ ```
584
+
585
+ #### Proc
586
+
587
+ You can use a `Proc` to return a `String` or `Arel::Attributes::Attribute` as above.
588
+
589
+ ```ruby
590
+ @hosts_grid = initialize_grid(Host,
591
+ custom_order: {
592
+ 'hosts.ip_address' => lambda{|f| Arel.sql(request[:numeric_sorting] ? "INET_ATON( #{f} )" : f) }
593
+ })
594
+ ```
595
+
596
+ ### Custom Sorting
597
+
598
+ While `:custom_order` lets you define SQL that determines the results order, you may want to sort the result by arbritrary Ruby code. The `:sort_by` option on columns lets you define a `Proc` that determines the sorting on that column. This `Proc` is passed to Ruby's `Enumerable#sort_by`.
599
+
600
+ ```ruby
601
+ grid.column name: 'Status Name', attribute: 'name', sort_by: ->(status) { [status.number_of_vowels, status] }
602
+ ```
603
+
604
+ You can also use `:sort_by` to add sorting on values that are not columns in the database. In this case, you must also define an arbitrary `:attribute` option that serves as the request's sort key parameter.
605
+
606
+ ```ruby
607
+ grid.column name: 'Task Count', attribute: 'task_count', sort_by: ->(status) { status.tasks.count } do |status|
608
+ status.tasks.count
609
+ end
610
+ ```
611
+
612
+ Note that `sort_by` will load all records into memory to sort them (even the ones not on the current page), so it may not be appropriate for use with a large number of results.
613
+
614
+ ## Filters
615
+
616
+ Each column filter type is supported by a `column processor`. Each `column processor` is
617
+ responsible for
618
+
619
+ * generating HTML and supporting Javascript for the filter, input fields, dropdowns, javascript calendars, etc
620
+ * converting HTTP parameters from those input fields into ActiveRelation instances
621
+
622
+ By default column filters depend on the type of the underlying database column.
623
+
624
+ You can override these defaults in two ways:
625
+
626
+ * defining a custom filter with `:custom_filter`. Read more about it section "Custom dropdown filters".
627
+ * overriding the `column processor` type with `:filter_type`.
628
+
629
+ Which Column Processor is instantiated for which data types is defined in file
630
+ `lib/wice/columns/column_processor_index.rb`:
631
+
632
+ ```ruby
633
+ module Wice
634
+ module Columns
635
+ COLUMN_PROCESSOR_INDEX = ActiveSupport::OrderedHash[ #:nodoc:
636
+ :action, 'column_action', # Special processor for action column, columns with checkboxes
637
+ :text, 'column_string',
638
+ :string, 'column_string',
639
+ :rails_datetime_helper, 'column_rails_datetime_helper', # standard Rails datepicker helper
640
+ :rails_date_helper, 'column_rails_date_helper', # standard Rails date helper
641
+ :jquery_datepicker, 'column_jquery_datepicker',
642
+ :bootstrap_datepicker, 'column_bootstrap_datepicker',
643
+ :html5_datepicker, 'column_html5_datepicker', # not ready
644
+ :integer, 'column_integer',
645
+ :range, 'column_range',
646
+ :float, 'column_float',
647
+ :decimal, 'column_float',
648
+ :custom, 'column_custom_dropdown', # Special processor for custom filter columns
649
+ :boolean, 'column_boolean'
650
+ ]
651
+ end
652
+ end
653
+ ```
654
+
655
+ A good example for using `:filter_type` to change th default is numeric columns. By default
656
+ `'column_integer'` is instantiated for `integer` columns, and it renders one input field.
657
+ But it is also possible to use another Column Processor called `'column_range'` which renders two
658
+ input fields and searches for values in the given the range instead of searching for values which equal
659
+ the given search term.
660
+
661
+ It also possible to define and use your own column processors outside of the plugin, in you application.
662
+ Read more about this in section "Defining your own external filter processors".
663
+
664
+
665
+ ### Custom dropdown filters
666
+
667
+ It is possible to construct custom dropdown filters. A custom dropdown filter is essentially a dropdown
668
+ list.
669
+
670
+ Depending on the value of `column` parameter`:custom_filter` different modes are available:
671
+
672
+
673
+ #### Array of two-element arrays or a hash
674
+
675
+ An array of two-element arrays or a hash are semantically identical ways of creating a custom filter.
676
+
677
+ Every first item of the two-element array is used for the label of the select option while the second
678
+ element is the value of the select option. In case of a hash the keys become the labels of the generated
679
+ dropdown list, while the values will be values of options of the dropdown list:
680
+
681
+ ```ruby
682
+ g.column name: 'Status', attribute: 'status',
683
+ custom_filter: {'Development' => 'development', 'Testing' => 'testing', 'Production' => 'production'}
684
+
685
+ g.column name: 'Status', attribute: 'status',
686
+ custom_filter: [['Development', 'development'], ['Testing', 'testing'], ['Production', 'production']]
687
+ ```
688
+
689
+ It is also possible to submit a array of strings or numbers, in this case every item will be used both as
690
+ the value of the select option and as its label:
691
+
692
+ ```ruby
693
+ g.column name: 'Status', attribute: 'status', custom_filter: ['development', 'testing', 'production']
694
+ ```
695
+
696
+ #### :auto
697
+
698
+ `:auto` - a powerful option which populates the dropdown list with all unique values of the column
699
+ specified by `:attribute` and `:assoc`, if present.
700
+
701
+ ```ruby
702
+ g.column name: 'Status', attribute: 'status', custom_filter: :auto
703
+ ```
704
+
705
+ In the above example all statuses will appear in the dropdown even if they don't appear in the current
706
+ resultset.
707
+
708
+
709
+ #### Custom filters and associations (joined tables)
710
+
711
+ In most cases custom fields are needed for one-to-many and many-to-many associations.
712
+
713
+ To correctly build a filter condition foreign keys have to be used, not the actual values rendered in the
714
+ column.
715
+
716
+ For example, if there is a column:
717
+
718
+ ```ruby
719
+ g.column name: 'Project Name', attribute: 'name', assoc: :project do |task|
720
+ task.project.name if task.project
721
+ end
722
+ ```
723
+
724
+ adding `:custom_filter` like this:
725
+
726
+ ```ruby
727
+ g.column name: 'Project Name', attribute: 'name', assoc: :project,
728
+ custom_filter: Project.find(:all).map{|pr| [pr.name, pr.name]} do |task|
729
+ task.project.name if task.project
730
+ end
731
+ ```
732
+
733
+ is bad style and can fail, because the resulting condition will compare the name of the project,
734
+ `projects.name` to a string, and in some databases it is possible that different records
735
+ (projects in our example) have the same name.
736
+
737
+ To use filter with foreign keys, it is advised to change the declaration of the column from
738
+ `projects.name`, to `tasks.project_id`, and build the dropdown with foreign keys as values:
739
+
740
+ ```ruby
741
+ g.column name: 'Project Name', attribute: 'tasks.project_id',
742
+ custom_filter: Project.find(:all).map{|pr| [pr.id, pr.name]} do |task|
743
+ task.project.name if task.project
744
+ end
745
+ ```
746
+
747
+ However, this will break the ordering of the column - the column will be ordered by the integer foreign
748
+ key. To fix this, we can override the ordering using `:custom_order`:
749
+
750
+ ```ruby
751
+ @tasks_grid = initialize_grid(Task,
752
+ include: :project,
753
+ custom_order: {
754
+ 'tasks.project_id' => 'projects.name'
755
+ }
756
+ )
757
+ ```
758
+
759
+ #### Any other symbol (method name) or an array of symbols (method names)
760
+
761
+
762
+ For one symbol (different from `:auto`) the dropdown list is populated by all unique values returned
763
+ by the method with this name sent to <em>all</em> ActiveRecord objects throughout all pages.
764
+
765
+ The conditions set up by the user are ignored, that is, the records used are all those found on all pages
766
+ without any filters active.
767
+
768
+ For an array of symbols, the first method name is sent to the ActiveRecord object if it responds to this
769
+ method, the second method name is sent to the returned value unless it is `nil`, and so on. In other
770
+ words, a single symbol mode is the same as an array of symbols where the array contains just one element.
771
+
772
+ ```ruby
773
+ g.column name: 'Version', attribute: 'expected_version_id', custom_filter: [:expected_version, :to_option] do |task|
774
+ task.expected_version.name if task.expected_version
775
+ end
776
+ ```
777
+
778
+ There are two important differences from `:auto`:
779
+
780
+ 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.
781
+ 2. Filtering by any option of such a custom filter will bring a non-empty list, unlike with `:auto`.
782
+
783
+
784
+ This mode has one major drawback - this mode requires an additional query without `offset` and `limit`
785
+ clauses to instantiate _all_ ActiveRecord objects, and performance-wise it brings all the advantages of
786
+ pagination to nothing. Thus, memory- and performance-wise this can be really bad for some queries and
787
+ tables and should be used with care.
788
+
789
+
790
+ If the final method returns a atomic value like a string or an integer, it is used for both the value and
791
+ the label of the select option element:
792
+
793
+ ```html
794
+ <option value="returned value">returned value</option>
795
+ ```
796
+
797
+ However, if the retuned value is a two element array, the first element is used for the option label and
798
+ the second - for the value.
799
+
800
+ Typically, a model method like the following:
801
+
802
+ ```ruby
803
+ def to_option
804
+ [name, id]
805
+ end
806
+ ```
807
+
808
+ together with
809
+
810
+ ```ruby
811
+ custom_filter: :to_option
812
+ ```
813
+
814
+ would do the trick:
815
+
816
+ ```html
817
+ <option value="id">name</option>
818
+ ```
819
+
820
+ Alternatively, a hash with the single key-value pair can be used, where the key will be used for the
821
+ label, and the key - for the value:
822
+
823
+ ```ruby
824
+ def to_option
825
+ {name => id}
826
+ end
827
+ ```
828
+
829
+ #### Special treatment of values 'null' and 'not null'
830
+
831
+ Values `null` and `not null` in a generated custom filter are treated specially, as SQL `null` statement
832
+ and not as strings. Value `null` is transformed into SQL condition `IS NULL`, and `not null` into
833
+ `IS NOT NULL`.
834
+
835
+ Thus, if in a filter defined by
836
+
837
+ ```ruby
838
+ custom_filter: {'No' => 'null', 'Yes' => 'not null', '1' => 1, '2' => '2', '3' => '3'}
839
+ ```
840
+
841
+ values '1', '2' and 'No' are selected (in a multi-select mode), this will result in the following SQL:
842
+
843
+ ```sql
844
+ ( table.field IN ( '1', '2' ) OR table.field IS NULL )
845
+ ```
846
+
847
+ #### Multiple selection
848
+
849
+ By default it is possible for any dropdown list to switch between single and multiple selection modes.
850
+ To only allow single selection use `:allow_multiple_selection`:
851
+
852
+ ```ruby
853
+ g.column name: 'Expected in version', attribute: 'expected_version_id',
854
+ custom_filter: [:expected_version, :to_option], allow_multiple_selection: false do |task|
855
+ ...
856
+ end
857
+ ```
858
+
859
+ ### Numeric Filters
860
+
861
+ Before version 3.2.1 the filter used for numeric columns was a range filter with two limits. Beginning
862
+ with version 3.2.1 the default is a direct comparison filter with one input field. The old range filter
863
+ can still be loaded using parameter `:filter_type` with value `:range`:
864
+
865
+ ```ruby
866
+ g.column filter_type: :range do |task|
867
+ ...
868
+ end
869
+ ```
870
+
871
+ ### Date and DateTime Filters
872
+
873
+ WiceGrid provides four filters for selecting dates and time:
874
+
875
+ * ```:jquery_datepicker``` - Jquery datepicker (works for datetime, too)
876
+ * ```:bootstrap_datepicker``` - Bootstrap datepicker (works for datetime, too)
877
+ * ```:rails_date_helper``` - standard Rails date helper
878
+ * ```:rails_datetime_helper``` - standard Rails datetime helper
879
+
880
+ Specify a date/datetime filter just like you specify any other filter:
881
+
882
+ ```
883
+ g.column name: 'Updated', attribute: 'updated_at', filter_type: :rails_datetime_helper do |task|
884
+ task.updated_at.to_s(:db)
885
+ end
886
+ ```
887
+
888
+ Default filters are defined in configuration constants Wice::Defaults::DEFAULT_FILTER_FOR_DATE and
889
+ Wice::Defaults::DEFAULT_FILTER_FOR_DATETIME.
890
+
891
+
892
+
893
+ #### jQuery UI DatePicker `(HELPER_STYLE = :calendar)`
894
+
895
+ By default WiceGrid uses jQuery UI datepicker[http://jqueryui.com/demos/datepicker/] for Date and DateTime
896
+ filters. Because this is part of the standard jQuery UI codebase, it is not bundled together with the
897
+ plugin, and it is the responsibility of the programmer to include all necessary assets including
898
+ localization files if the application is multilingual.
899
+
900
+ jQuery UI datepicker does not have any time related controls, and when dealing with DateTime filters, the
901
+ time value is ignored.
902
+
903
+ Constants `DATE_FORMAT` and `DATETIME_FORMAT` in the configuration file define the format of dates the
904
+ user will see, as well as the format of the string sent in a HTTP parameter. If you change the formats,
905
+ make sure that lamdbas defined in `DATETIME_PARSER` and `DATE_PARSER` return valid DateTime and Date
906
+ objects.
907
+
908
+ jQuery `datepicker` uses a different format flavor, therefore there is an additional constant
909
+ `DATE_FORMAT_JQUERY`. While `DATE_FORMAT_JQUERY` is fed to `datepicker`, `DATE_FORMAT` is still used
910
+ for presenting initial date values in filters, so make sure that `DATE_FORMAT_JQUERY` and `DATE_FORMAT`
911
+ result in an identical date representation.
912
+
913
+ Constant `DATEPICKER_YEAR_RANGE` defines the range of years in the Datepicker year dropdown. Alternatively,
914
+ you can always change this range dynamically with the following javascript:
915
+
916
+ ```js
917
+ $( ".hasDatepicker" ).datepicker( "option", "yearRange", "2000:2042" );
918
+ ```
919
+
920
+ #### jQuery UI DatePicker `(HELPER_STYLE = :bootstrap)`
921
+
922
+ WiceGrid also supports [Bootstrap Datepicker](https://github.com/Nerian/bootstrap-datepicker-rails).
923
+
924
+ #### Rails standard input fields `(HELPER_STYLE = :standard)`
925
+
926
+ Another option is standard Rails helpers for date fields, these are separate select fields for years,
927
+ months and days (also for hour and minute if it is a datetime field).
928
+
929
+ ### Detached Filters
930
+
931
+ Filters can also be detached from the grid table and placed anywhere on page.
932
+
933
+ This is a 3-step process.
934
+
935
+ First, define the grid with helper `define_grid` instead of `grid`. Everything should be done the same way
936
+ as with `grid`, but every column which will have an external filter, add
937
+ `detach_with_id: :some_filter_name`` in the column definition. The value of `:detach_with_id` is an
938
+ arbitrary string or a symbol value which will be used later to identify the filter.
939
+
940
+ ```erb
941
+ <%= define_grid(@tasks_grid, show_filters: :always) do |g|
942
+
943
+ g.column name: 'Title', attribute: 'title', detach_with_id: :title_filter do |task|
944
+ link_to('Edit', edit_task_path(task.title))
945
+ end
946
+
947
+ g.column name: 'Archived', attribute: 'archived', detach_with_id: :archived_filter do |task|
948
+ task.archived? ? 'Yes' : 'No'
949
+ end
950
+
951
+ g.column name: 'Added', attribute: 'created_at', detach_with_id: :created_at_filter do |task|
952
+ task.created_at.to_s(:short)
953
+ end
954
+
955
+ end -%>
956
+ ```
957
+
958
+ Then, use `grid_filter(grid, :some_filter_name)` to render filters:
959
+
960
+ ```erb
961
+ <% # rendering filter with key :title_filter %>
962
+ <%= grid_filter @tasks_grid, :title_filter %>
963
+
964
+ <% # rendering filter with key :archived_filter %>
965
+ <%= grid_filter @tasks_grid, :archived_filter %>
966
+
967
+ <% # rendering filter with key :created_at_filter %>
968
+ <%= grid_filter @tasks_grid, :created_at_filter %>
969
+
970
+ <% # Rendering the grid body %>
971
+ <%= grid(@tasks_grid) %>
972
+ ```
973
+
974
+ Finally, use `render_grid(@grid)` to actually output the grid table.
975
+
976
+
977
+ Using custom submit and reset buttons together with `hide_submit_button: true` and
978
+ `hide_reset_button: true` allows to completely get rid of the default filter row and the default
979
+ icons (see section 'Submit/Reset Buttons').
980
+
981
+
982
+ If a column was declared with `:detach_with_id`, but never output with `grid_filter`, filtering
983
+ the grid in development mode will result in an warning javascript message and the missing filter will be
984
+ ignored. There is no such message in production.
985
+
986
+
987
+ ### Defining your own external filter processors
988
+
989
+
990
+ It possible to define and use your own column processors outside of the plugin, in you application.
991
+
992
+ The first step is to edit `Wice::Defaults::ADDITIONAL_COLUMN_PROCESSORS` in
993
+ `wice_grid_config.rb`:
994
+
995
+ ```ruby
996
+
997
+ Wice::Defaults::ADDITIONAL_COLUMN_PROCESSORS = {
998
+ my_own_filter: ['ViewColumnMyOwnFilter', 'ConditionsGeneratorMyOwnFilter'],
999
+ another_filter: ['ViewColumnAnotherFilter', 'ConditionsGeneratorAnotherFilter']
1000
+ }
1001
+ ```
1002
+
1003
+ The first element in the two-item array is the name of a class responsible for rendering
1004
+ the filter view. The second element is the name of a class responsible for processing
1005
+ filter parameters.
1006
+
1007
+ For examples of these two classes look at the existing column processors in `lib/wice/columns/`
1008
+
1009
+ The structure of these two classes is as follows:
1010
+
1011
+ ```ruby
1012
+ class ViewColumnMyOwnFilter < Wice::Columns::ViewColumn
1013
+
1014
+ def render_filter_internal(params)
1015
+ ...
1016
+ end
1017
+
1018
+ def yield_declaration_of_column_filter
1019
+ {
1020
+ templates: [...],
1021
+ ids: [...]
1022
+ }
1023
+ end
1024
+ end
1025
+
1026
+
1027
+ class ConditionsGeneratorMyOwnFilter < Wice::Columns::ConditionsGeneratorColumn
1028
+
1029
+ def generate_conditions(table_name, opts)
1030
+ ...
1031
+ end
1032
+
1033
+ end
1034
+ ```
1035
+
1036
+ To use an external column processor use `:filter_type` in a column definition:
1037
+
1038
+ ```ruby
1039
+ column name: 'name', attribute: 'attribute', filter_type: :my_own_filter do |rec|
1040
+ ...
1041
+ end
1042
+ ```
1043
+
1044
+ ## Defaults
1045
+
1046
+ Default values like can be changed in `config/initializers/wice_grid_config.rb`.
1047
+
1048
+ ## Submit/Reset buttons
1049
+ Instead of using default Submit and Reset icons you can use external HTML elements to trigger
1050
+ these actions. Add a button or any other clickable HTML element with class
1051
+ `wg-external-submit-button` or `wg-external-reset-button`, and attribute `data-grid-name`
1052
+ whose value is the name of the grid:
1053
+
1054
+ ```html
1055
+ <button class="wg-external-submit-button" data-grid-name="grid">Submit</button>
1056
+ <button class="wg-external-reset-button" data-grid-name="grid">Reset</button>
1057
+ ```
1058
+
1059
+ To hide the default icons use `hide_submit_button: true` and
1060
+ `hide_reset_button: true` in the `grid` helper.
1061
+
1062
+
1063
+ ## Auto-reloading filters
1064
+
1065
+ It is possible to configure a grid to reload itself once a filter has been changed. It works with all
1066
+ filter types including the JS calendar, the only exception is the standard Rails date/datetime filters.
1067
+
1068
+ Use option `:auto_reload` in the column definiton:
1069
+
1070
+ ```erb
1071
+
1072
+ <%= grid(@tasks_grid, show_filters: :always, hide_submit_button: true) do |g|
1073
+
1074
+ # String
1075
+ g.column name: 'Title', attribute: 'title', auto_reload: true
1076
+
1077
+ # Boolean
1078
+ g.column name: 'Archived', attribute: 'archived', auto_reload: true
1079
+
1080
+ # Custom (dropdown)
1081
+ g.column name: 'Status', attribute: 'status_id', custom_filter: Status.to_dropdown, auto_reload: true do |task|
1082
+ task.status.name if task.status
1083
+ end
1084
+
1085
+ # Datetime
1086
+ g.column name: 'Added', attribute: 'created_at', auto_reload: true, helper_style: :calendar do |task|
1087
+ task.created_at.to_s(:short)
1088
+ end
1089
+
1090
+ end -%>
1091
+ ```
1092
+
1093
+ To make this behavior default change constant `AUTO_RELOAD` in the configuration file.
1094
+
1095
+ ## Styling the grid
1096
+
1097
+
1098
+ ### Adding classes and styles
1099
+
1100
+ The `grid` helper accepts parameter `:html` which is a hash of HTML attributes for the table tag.
1101
+
1102
+ Another `grid` parameter is `header_tr_html` which is a hash of HTML attributes to
1103
+ be added to the first `tr` tag (or two first `tr`'s if the filter row is present).
1104
+
1105
+ `:html` is a parameter for the `column` method setting HTML attributes of `td` tags for a certain column.
1106
+
1107
+ ### Adding classes and styles dynamically
1108
+
1109
+ WiceGrid offers ways to dynamically add classes and styles to `TR` and `TD` based on the current ActiveRecord instance.
1110
+
1111
+
1112
+ For `<TD>`, let the `column` return an array where the first item is the usual
1113
+ string output whole the second is a hash of HTML attributes to be added for the
1114
+ `<td>` tag of the current cell:
1115
+
1116
+ ```ruby
1117
+ g.column do |portal_application|
1118
+ css_class = portal_application.public? ? 'public' : 'private'
1119
+ [portal_application.name, {class: css_class}]
1120
+ end
1121
+ ```
1122
+
1123
+ For adding classes/styles to `<TR>` use special clause `row_attributes` ,
1124
+ similar to `column`, only returning a hash:
1125
+
1126
+ ```erb
1127
+ <%= grid(@versions_grid) do |g|
1128
+ g.row_attributes do |version|
1129
+ if version.in_production?
1130
+ {style: 'background-color: rgb(255, 255, 204);'}
1131
+ end
1132
+ end
1133
+
1134
+ g.column{|version| ... }
1135
+ g.column{|version| ... }
1136
+ end -%>
1137
+ ```
1138
+
1139
+ Naturally, there can be only one `row_attributes` definition for a WiceGrid instance.
1140
+
1141
+ Various classes do not overwrite each other, instead, they are concatenated.
1142
+
1143
+
1144
+ ## Adding rows to the grid
1145
+
1146
+ It is possible to add your own handcrafted HTML after and/or before each grid row.
1147
+ This works similar to `row_attributes`, by adding blocks `after_row`, `before_row`, and `last_row`:
1148
+
1149
+ ```erb
1150
+ <%= grid(@tasks_grid) do |g|
1151
+ g.before_row do |task, number_of_columns|
1152
+ if task.active?
1153
+ "<tr><td colspan=\"10\">Custom line for #{t.name}</td></tr>" # this would add a row
1154
+ # before every active task row
1155
+ else
1156
+ nil
1157
+ end
1158
+ end
1159
+
1160
+ g.last_row do |number_of_columns| # This row will always be added to the bottom of the grid
1161
+ content_tag(:tr,
1162
+ content_tag(:td,
1163
+ 'Last row',
1164
+ colspan: 10),
1165
+ class: 'last_row')
1166
+ end
1167
+
1168
+ .......
1169
+ end %>
1170
+ ```
1171
+
1172
+ It is up for the developer to return the correct HTML code, or return `nil` if no row is needed for this record.
1173
+ Naturally, there is only one `before_row` definition and one `after_row` definition for a WiceGrid instance.
1174
+
1175
+ The second variable injected into to `before_row` and `after_row` block, and the first parameter injected
1176
+ into the `last_row` is the number of columns in the current grid.
1177
+
1178
+ ## Rendering a grid without records
1179
+
1180
+ If the grid does not contain any records to show, it is possible show some alternative view instead of
1181
+ an empty grid. Bear in mind that if the user sets up the filters in such a way that the selection of
1182
+ records is empty, this will still render the grid and it will be possible to reset the grid clicking
1183
+ on the Reset button. Thus, this only works if the initial number of records is 0.
1184
+
1185
+ ```erb
1186
+ <%= grid(@grid) do |g|
1187
+
1188
+ g.blank_slate do
1189
+ "There are no records"
1190
+ end
1191
+
1192
+ g.column do |product|
1193
+ ...
1194
+ end
1195
+ end -%>
1196
+ ```
1197
+
1198
+ There are two alternative ways to do the same, submitting a string to `blank_slate`:
1199
+
1200
+ ```ruby
1201
+ g.blank_slate "some text to be rendered"
1202
+ ```
1203
+
1204
+ Or a partial:
1205
+
1206
+ ```ruby
1207
+ g.blank_slate partial: "partial_name"
1208
+ ```
1209
+
1210
+ ## Action Column
1211
+
1212
+ It is possible to add a column with checkboxes for each record. This is useful for actions with multiple records,
1213
+ for example, deleting selected records. Please note that `action_column` only creates the checkboxes and the
1214
+ 'Select All' and 'Deselect All' buttons, and the form itself as well as processing the parameters should be
1215
+ taken care of by the application code.
1216
+
1217
+ ```erb
1218
+ <%= grid(@tasks_grid, show_filters: :always) do |g|
1219
+
1220
+ ...
1221
+
1222
+ g.action_column
1223
+
1224
+ ...
1225
+
1226
+ end -%>
1227
+ ```
1228
+
1229
+ By default the name of the HTTP parameter follows pattern `"#{grid_name}[#{param_name}][]"`, thus
1230
+ `params[grid_name][param_name]` will contain an array of object IDs.
1231
+
1232
+ You can hide a certain action checkbox if you add the usual block to `g.action_column`, just like with the
1233
+ `g.column` definition. If the block returns `nil` or `false` no checkbox will be rendered.
1234
+
1235
+ ```erb
1236
+ <%= grid(@tasks_grid, show_filters: :always) do |g|
1237
+
1238
+ ...
1239
+
1240
+ g.action_column do |task|
1241
+ task.finished?
1242
+ end
1243
+
1244
+ ...
1245
+
1246
+ end -%>
1247
+ ```
1248
+
1249
+ WiceGrid is form-friendly: submitting grid in a form retains the state of the form.
1250
+
1251
+
1252
+
1253
+ ## Integration of the grid with other forms on page
1254
+
1255
+ Imagine that the user should be able to change the behavior of the grid using some other control
1256
+ on the page, and not a grid filter.
1257
+
1258
+ For example, on a page showing tasks, change between 'Show active tasks' to 'Show archived tasks' using a dropdown box.
1259
+ WiceGrid allows to keep the status of the grid with all the filtering and sorting using helper
1260
+ `dump_filter_parameters_as_hidden_fields` which takes a grid object and dumps
1261
+ all current sorting and filtering parameters as hidden fields. Just include
1262
+ `dump_filter_parameters_as_hidden_fields(@grid)` inside your form, and the newly rendered grid will keep ordering and filtering.
1263
+
1264
+ ```erb
1265
+ <% form_tag('', method: :get) do %>
1266
+ <%= dump_filter_parameters_as_hidden_fields(@tasks_grid) %>
1267
+ <%= select_tag 'archived',
1268
+ options_for_select([['View active tasks', 0], ['View archived tasks', 1]], @archived ? 1 : 0),
1269
+ onchange: 'this.form.submit()' %>
1270
+ <% end -%>
1271
+ ```
1272
+
1273
+
1274
+ ## Show All Records
1275
+
1276
+ It is possible to switch to the All Records mode clicking on link "show all" in the bottom right corner.
1277
+ This functionality should be used with care. To turn this mode off for all grid instances,
1278
+ change constant `ALLOW_SHOWING_ALL_RECORDS` in `config/initializers/wice_grid_config.rb` to
1279
+ `false`. To do so for a specific grid, use initializer parameter `:allow_showing_all_records`.
1280
+
1281
+ Configuration constant `START_SHOWING_WARNING_FROM` sets the threshold number of all records after
1282
+ which clicking on the link results in a javascript confirmation dialog.
1283
+
1284
+
1285
+ ## CSV Export
1286
+
1287
+ It is possible to export the data displayed on a grid to a CSV file. The dumped data is the current resultset
1288
+ with all the current filters and sorting applied, only without the pagination constraint (i.e. all pages).
1289
+
1290
+ To enable CSV export add parameters `enable_export_to_csv` and `csv_file_name` to the initialization of the grid:
1291
+
1292
+ ```ruby
1293
+ @projects_grid = initialize_grid(Project,
1294
+ include: [:customer, :supplier],
1295
+ name: 'g2',
1296
+ enable_export_to_csv: true,
1297
+ csv_file_name: 'projects'
1298
+ )
1299
+ ```
1300
+
1301
+ `csv_file_name` is the name of the downloaded file. This parameter is optional, if it is missing, the name of
1302
+ the grid is used instead. The export icon will appear at the bottom right corner of the grid. If the program you are importing the generated CSV into has problem processing UTF-8, you can change the character encoding using the `csv_encoding` option. P.e. setting `csv_encoding: 'CP1252:UTF-8'` will make older versions of Excel happy. The format used is `<output encoding>:<input encoding>`.
1303
+
1304
+ Next, each grid view helper should be placed in a partial of its own, requiring it from the master
1305
+ template for the usual flow. There must be no HTML or ERB code in this partial except for the grid helper.
1306
+
1307
+ By convention the name of such a partial follows the following pattern:
1308
+
1309
+ ```
1310
+ _GRID_NAME_grid.html.erb
1311
+ ```
1312
+
1313
+ In other words, a grid named `tasks` is expected to be found in a template called
1314
+ `_tasks_grid.html.erb` (remember that the default name of grids is '`grid`'.)
1315
+
1316
+ Next, method `export_grid_if_requested` should be added to the end of each action
1317
+ containing grids with enabled CSV export.
1318
+
1319
+ `export_grid_if_requested` intercepts CSV export requests and evaluates the partial with the required grid helper.
1320
+
1321
+ The naming convention for grid partials can be easily overridden by supplying a hash parameter
1322
+ to `export_grid_if_requested` where each key is the name of a grid, and the value is the name of
1323
+ the template (like it is specified for `render`, i.e. without '_' and extensions):
1324
+
1325
+ ```ruby
1326
+ export_grid_if_requested('g1' => 'tasks_grid', 'g2' => 'projects_grid')
1327
+ ```
1328
+
1329
+ If the request is not a CSV export request, `export_grid_if_requested` does nothing and returns
1330
+ `false`, if it is a CSV export request, the method returns `true`.
1331
+
1332
+
1333
+ If the action has no explicit `render` call, it's OK to just place `export_grid_if_requested`
1334
+ as the last line of the action:
1335
+
1336
+ ```ruby
1337
+ def index
1338
+
1339
+ @tasks_grid = initialize_grid(Task,
1340
+ name: 'g1',
1341
+ enable_export_to_csv: true,
1342
+ csv_file_name: 'tasks'
1343
+ )
1344
+
1345
+ @projects_grid = initialize_grid(Project,
1346
+ name: 'g2',
1347
+ enable_export_to_csv: true,
1348
+ csv_file_name: 'projects'
1349
+ )
1350
+
1351
+ export_grid_if_requested
1352
+ end
1353
+ ```
1354
+
1355
+ Otherwise, to avoid double rendering, use the return value of the method to conditionally call your `render` :
1356
+
1357
+ ```ruby
1358
+
1359
+ def index
1360
+
1361
+ ...........
1362
+
1363
+ export_grid_if_requested || render(action: 'my_template')
1364
+ end
1365
+ ```
1366
+
1367
+ It's also possible to supply a block which will be called if no CSV export is requested:
1368
+
1369
+ ```ruby
1370
+ def index
1371
+
1372
+ ...........
1373
+
1374
+ export_grid_if_requested do
1375
+ render(action: 'my_template')
1376
+ end
1377
+ end
1378
+ ```
1379
+
1380
+ If a column has to be excluded from the CSV export,
1381
+ set `column` parameter `in_csv` to `false`:
1382
+
1383
+ ```ruby
1384
+ g.column in_csv: false do |task|
1385
+ link_to('Edit', edit_task_path(task))
1386
+ end
1387
+ ```
1388
+
1389
+ If a column must appear both in HTML and CSV, but with different output, duplicate the column and use
1390
+ parameters `in_csv` and `in_html` to include one of them to html output only, the other to CSV only:
1391
+
1392
+ ```ruby
1393
+ # html version
1394
+ g.column name: 'Title', attribute: 'title', in_csv: false do |task|
1395
+ link_to('Edit', edit_task_path(task.title))
1396
+ end
1397
+ # plain text version
1398
+ g.column name: 'Title', in_html: false do |task|
1399
+ task.title
1400
+ end
1401
+ ```
1402
+
1403
+ The default field separator in generated CSV is a comma, but it's possible to override it:
1404
+
1405
+ ```ruby
1406
+ @products_grid = initialize_grid(Product,
1407
+ enable_export_to_csv: true,
1408
+ csv_field_separator: ';',
1409
+ csv_file_name: 'products'
1410
+ )
1411
+ ```
1412
+
1413
+ If you need an external CSV export button , add class `wg-external-csv-export-button`
1414
+ to any clickable element on page and set its attribute `data-grid-name` to the name of the grid:
1415
+
1416
+ ```html
1417
+ <button class="wg-external-csv-export-button" data-grid-name="grid">Export To CSV</button>
1418
+ ```
1419
+
1420
+ If you need to disable the default export icon in the grid, add `hide_csv_button: true` to the `grid` helper.
1421
+
1422
+
1423
+ ## Access to Records From Outside The Grid
1424
+
1425
+ There are two ways you can access the records outside the grid - using methods of the WiceGrid
1426
+ object and using callbacks.
1427
+
1428
+ ### Accessing Records Via The WiceGrid Object
1429
+
1430
+ Method `current_page_records` returns exactly the same list of objects displayed on page:
1431
+
1432
+ ```erb
1433
+ <%= grid(@tasks_grid) do |g|
1434
+ ...
1435
+ end -%>
1436
+
1437
+ <p>
1438
+ IDs of records on the current page:
1439
+ <%= @tasks_grid.current_page_records.map(&:id).to_sentence %>
1440
+ </p>
1441
+ ```
1442
+
1443
+ Method `all_pages_records` returns a list of objects browsable through all pages with the current filters:
1444
+
1445
+ ```erb
1446
+ <%= grid(@tasks_grid) do |g|
1447
+ ...
1448
+ end -%>
1449
+
1450
+ <p>
1451
+ IDs of all records:
1452
+ <%= @tasks_grid.all_pages_records.map(&:id).to_sentence %>
1453
+ </p>
1454
+ ```
1455
+
1456
+ Mind that this helper results in an additional SQL query.
1457
+
1458
+
1459
+ Because of the current implementation of WiceGrid these helpers work only after the declaration
1460
+ of the grid in the view.
1461
+ This is due to the lazy nature of WiceGrid - the actual call to the database is made during
1462
+ the execution of
1463
+ the `grid` helper, because to build the correct query columns declarations are required.
1464
+
1465
+ ### Accessing Records Via Callbacks
1466
+
1467
+ It is possible to set up callbacks which are executed from within the plugin just after the call to the database.
1468
+ The callbacks are called before rendering the grid cells, so the results of this processing can be used in the grid.
1469
+ There are 3 ways you can set up such callbacks:
1470
+
1471
+ Via a lambda object:
1472
+
1473
+ ```ruby
1474
+ def index
1475
+ @tasks_grid = initialize_grid(Task,
1476
+ with_paginated_resultset: ->(records){
1477
+ ...
1478
+ }
1479
+ )
1480
+ end
1481
+ ```
1482
+
1483
+ Via a symbol which is the name of a controller method:
1484
+
1485
+ ```ruby
1486
+ def index
1487
+ @tasks_grid = initialize_grid(Task,
1488
+ with_paginated_resultset: :process_selection
1489
+ )
1490
+ end
1491
+
1492
+ def process_selection(records)
1493
+ ...
1494
+ end
1495
+ ```
1496
+
1497
+ Via a separate block:
1498
+
1499
+ ```ruby
1500
+ def index
1501
+ @tasks_grid = initialize_grid(Task)
1502
+
1503
+ @tasks_grid.with_paginated_resultset do |records|
1504
+ ...
1505
+ end
1506
+ end
1507
+ ```
1508
+
1509
+ There are two callbacks:
1510
+
1511
+ * `:with_paginated_resultset` - used to process records of the current page
1512
+ * `:with_resultset` - used to process all records browsable through all pages with the current filters
1513
+
1514
+ While the `:with_paginated_resultset` callback just receives the list of records, `:with_resultset`
1515
+ receives an ActiveRelation object which can be used to obtain the list of all records:
1516
+
1517
+ ```ruby
1518
+ def index
1519
+ @tasks_grid = initialize_grid(Task)
1520
+
1521
+ @tasks_grid.with_resultset do |active_relation|
1522
+ all_records = active_relation.all
1523
+ ...
1524
+ end
1525
+ end
1526
+ ```
1527
+
1528
+ This lazy nature exists for performance reasons.
1529
+ Reading all records leads to an additional call, and there can be cases when processing all records should be triggered
1530
+ only under certain circumstances:
1531
+
1532
+ ```ruby
1533
+ def index
1534
+ @tasks_grid = initialize_grid(Task)
1535
+
1536
+ @tasks_grid.with_resultset do |active_relation|
1537
+ if params[:process_all_records]
1538
+ all_records = active_relation.all
1539
+ ...
1540
+ end
1541
+ end
1542
+ end
1543
+ ```
1544
+
1545
+ ## Testing
1546
+
1547
+ To run tests:
1548
+
1549
+ 1. `git clone https://github.com/patricklindsay/wice_grid.git`
1550
+ 2. `cd wice_grid`
1551
+ 3. `bundle`
1552
+ 4. Install phantomjs (e.g. `brew install phantomjs` or `apt-get install phantomjs` or something else)
1553
+ 5. `bundle exec appraisal rspec`
1554
+
1555
+ Tests against Rails 5.0, 5.1 & 5.2. To test against a specific version, for example Rails 5.2 run `bundle exec appraisal rails-5.2 rspec`
1556
+
1557
+ This repository contains a Rails application for testing purposes. To fire up this application manually, run `cd spec/support/test_app/bin; RAILS_ENV=test rails s`.
1558
+
1559
+ ## Bug reports
1560
+
1561
+ If you discover a problem with Wicegrid, we would love to know about it. Please use the [GitHub issue tracker](https://github.com/patricklindsay/wice_grid/issues)