active_scaffold-sequel 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. data/CHANGELOG +179 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +36 -0
  4. data/app/assets/images/active_scaffold/add.gif +0 -0
  5. data/app/assets/images/active_scaffold/arrow_down.gif +0 -0
  6. data/app/assets/images/active_scaffold/arrow_up.gif +0 -0
  7. data/app/assets/images/active_scaffold/close.gif +0 -0
  8. data/app/assets/images/active_scaffold/close_touch.png +0 -0
  9. data/app/assets/images/active_scaffold/config.png +0 -0
  10. data/app/assets/images/active_scaffold/cross.png +0 -0
  11. data/app/assets/images/active_scaffold/gears.png +0 -0
  12. data/app/assets/images/active_scaffold/indicator-small.gif +0 -0
  13. data/app/assets/images/active_scaffold/indicator.gif +0 -0
  14. data/app/assets/images/active_scaffold/magnifier.png +0 -0
  15. data/app/assets/javascripts/active_scaffold.js.erb +19 -0
  16. data/app/assets/javascripts/jquery/active_scaffold.js +1057 -0
  17. data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +24 -0
  18. data/app/assets/javascripts/jquery/draggable_lists.js +27 -0
  19. data/app/assets/javascripts/jquery/jquery.editinplace.js +743 -0
  20. data/app/assets/javascripts/jquery/tiny_mce_bridge.js +7 -0
  21. data/app/assets/javascripts/prototype/active_scaffold.js +1052 -0
  22. data/app/assets/javascripts/prototype/dhtml_history.js +870 -0
  23. data/app/assets/javascripts/prototype/form_enhancements.js +117 -0
  24. data/app/assets/javascripts/prototype/rico_corner.js +370 -0
  25. data/app/assets/javascripts/prototype/tiny_mce_bridge.js +7 -0
  26. data/app/assets/stylesheets/active_scaffold-ie.css +35 -0
  27. data/app/assets/stylesheets/active_scaffold.css.scss +14 -0
  28. data/app/assets/stylesheets/active_scaffold_colors.css.scss +395 -0
  29. data/app/assets/stylesheets/active_scaffold_extensions.css.erb +2 -0
  30. data/app/assets/stylesheets/active_scaffold_images.css.scss +43 -0
  31. data/app/assets/stylesheets/active_scaffold_layout.css +912 -0
  32. data/app/assets/stylesheets/blue-theme.css +74 -0
  33. data/config/locales/de.yml +114 -0
  34. data/config/locales/en.yml +118 -0
  35. data/config/locales/es.yml +120 -0
  36. data/config/locales/fr.yml +121 -0
  37. data/config/locales/hu.yml +74 -0
  38. data/config/locales/ja.yml +73 -0
  39. data/config/locales/ru.yml +123 -0
  40. data/frontends/default/views/_action_group.html.erb +24 -0
  41. data/frontends/default/views/_add_existing_form.html.erb +30 -0
  42. data/frontends/default/views/_base_form.html.erb +51 -0
  43. data/frontends/default/views/_create_form.html.erb +8 -0
  44. data/frontends/default/views/_create_form_on_list.html.erb +6 -0
  45. data/frontends/default/views/_field_search.html.erb +32 -0
  46. data/frontends/default/views/_form.html.erb +24 -0
  47. data/frontends/default/views/_form_association.html.erb +15 -0
  48. data/frontends/default/views/_form_association_footer.html.erb +47 -0
  49. data/frontends/default/views/_form_attribute.html.erb +20 -0
  50. data/frontends/default/views/_form_hidden_attribute.html.erb +2 -0
  51. data/frontends/default/views/_form_messages.html.erb +5 -0
  52. data/frontends/default/views/_horizontal_subform.html.erb +28 -0
  53. data/frontends/default/views/_horizontal_subform_footer.html.erb +0 -0
  54. data/frontends/default/views/_horizontal_subform_header.html.erb +11 -0
  55. data/frontends/default/views/_horizontal_subform_record.html.erb +38 -0
  56. data/frontends/default/views/_human_conditions.html.erb +1 -0
  57. data/frontends/default/views/_list.html.erb +18 -0
  58. data/frontends/default/views/_list_actions.html.erb +15 -0
  59. data/frontends/default/views/_list_calculations.html.erb +16 -0
  60. data/frontends/default/views/_list_column_headings.html.erb +12 -0
  61. data/frontends/default/views/_list_header.html.erb +10 -0
  62. data/frontends/default/views/_list_inline_adapter.html.erb +10 -0
  63. data/frontends/default/views/_list_messages.html.erb +30 -0
  64. data/frontends/default/views/_list_pagination.html.erb +11 -0
  65. data/frontends/default/views/_list_pagination_links.html.erb +9 -0
  66. data/frontends/default/views/_list_record.html.erb +14 -0
  67. data/frontends/default/views/_list_record_columns.html.erb +8 -0
  68. data/frontends/default/views/_list_with_header.html.erb +36 -0
  69. data/frontends/default/views/_messages.html.erb +10 -0
  70. data/frontends/default/views/_render_field.js.erb +20 -0
  71. data/frontends/default/views/_row.html.erb +6 -0
  72. data/frontends/default/views/_search.html.erb +34 -0
  73. data/frontends/default/views/_search_attribute.html.erb +10 -0
  74. data/frontends/default/views/_show.html.erb +8 -0
  75. data/frontends/default/views/_show_columns.html.erb +15 -0
  76. data/frontends/default/views/_update_actions.html.erb +9 -0
  77. data/frontends/default/views/_update_form.html.erb +6 -0
  78. data/frontends/default/views/_vertical_subform.html.erb +12 -0
  79. data/frontends/default/views/_vertical_subform_record.html.erb +38 -0
  80. data/frontends/default/views/action_confirmation.html.erb +13 -0
  81. data/frontends/default/views/add_existing.js.erb +18 -0
  82. data/frontends/default/views/add_existing_form.html.erb +5 -0
  83. data/frontends/default/views/create.html.erb +5 -0
  84. data/frontends/default/views/delete.html.erb +13 -0
  85. data/frontends/default/views/destroy.js.erb +24 -0
  86. data/frontends/default/views/edit_associated.js.erb +12 -0
  87. data/frontends/default/views/field_search.html.erb +5 -0
  88. data/frontends/default/views/form_messages.js.erb +1 -0
  89. data/frontends/default/views/list.html.erb +1 -0
  90. data/frontends/default/views/on_action_update.js.erb +13 -0
  91. data/frontends/default/views/on_create.js.erb +47 -0
  92. data/frontends/default/views/on_mark_all.js.erb +12 -0
  93. data/frontends/default/views/on_update.js.erb +31 -0
  94. data/frontends/default/views/refresh_list.js.erb +1 -0
  95. data/frontends/default/views/render_field.js.erb +1 -0
  96. data/frontends/default/views/search.html.erb +5 -0
  97. data/frontends/default/views/show.html.erb +5 -0
  98. data/frontends/default/views/update.html.erb +8 -0
  99. data/frontends/default/views/update_column.js.erb +16 -0
  100. data/frontends/default/views/update_row.js.erb +1 -0
  101. data/lib/active_scaffold/actions/common_search.rb +25 -0
  102. data/lib/active_scaffold/actions/core.rb +197 -0
  103. data/lib/active_scaffold/actions/create.rb +148 -0
  104. data/lib/active_scaffold/actions/delete.rb +76 -0
  105. data/lib/active_scaffold/actions/field_search.rb +82 -0
  106. data/lib/active_scaffold/actions/list.rb +196 -0
  107. data/lib/active_scaffold/actions/mark.rb +75 -0
  108. data/lib/active_scaffold/actions/nested.rb +245 -0
  109. data/lib/active_scaffold/actions/search.rb +48 -0
  110. data/lib/active_scaffold/actions/show.rb +61 -0
  111. data/lib/active_scaffold/actions/subform.rb +23 -0
  112. data/lib/active_scaffold/actions/update.rb +150 -0
  113. data/lib/active_scaffold/active_record_permissions.rb +136 -0
  114. data/lib/active_scaffold/attribute_params.rb +208 -0
  115. data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +39 -0
  116. data/lib/active_scaffold/bridges/ancestry.rb +5 -0
  117. data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +67 -0
  118. data/lib/active_scaffold/bridges/calendar_date_select.rb +24 -0
  119. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +107 -0
  120. data/lib/active_scaffold/bridges/cancan.rb +15 -0
  121. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +31 -0
  122. data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge_helpers.rb +10 -0
  123. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +45 -0
  124. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +17 -0
  125. data/lib/active_scaffold/bridges/carrierwave.rb +12 -0
  126. data/lib/active_scaffold/bridges/country_helper/country_helper_bridge.rb +358 -0
  127. data/lib/active_scaffold/bridges/country_helper.rb +9 -0
  128. data/lib/active_scaffold/bridges/date_picker/ext.rb +45 -0
  129. data/lib/active_scaffold/bridges/date_picker/helper.rb +180 -0
  130. data/lib/active_scaffold/bridges/date_picker.rb +23 -0
  131. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge.rb +34 -0
  132. data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge_helpers.rb +10 -0
  133. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +27 -0
  134. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +16 -0
  135. data/lib/active_scaffold/bridges/dragonfly.rb +9 -0
  136. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +48 -0
  137. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +57 -0
  138. data/lib/active_scaffold/bridges/file_column/form_ui.rb +34 -0
  139. data/lib/active_scaffold/bridges/file_column/list_ui.rb +26 -0
  140. data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +43 -0
  141. data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +9 -0
  142. data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +15 -0
  143. data/lib/active_scaffold/bridges/file_column.rb +11 -0
  144. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +27 -0
  145. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +16 -0
  146. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +36 -0
  147. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +24 -0
  148. data/lib/active_scaffold/bridges/paperclip.rb +12 -0
  149. data/lib/active_scaffold/bridges/record_select/helpers.rb +86 -0
  150. data/lib/active_scaffold/bridges/record_select.rb +11 -0
  151. data/lib/active_scaffold/bridges/semantic_attributes/column.rb +20 -0
  152. data/lib/active_scaffold/bridges/semantic_attributes.rb +5 -0
  153. data/lib/active_scaffold/bridges/shared/date_bridge.rb +209 -0
  154. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +46 -0
  155. data/lib/active_scaffold/bridges/tiny_mce.rb +17 -0
  156. data/lib/active_scaffold/bridges.rb +61 -0
  157. data/lib/active_scaffold/config/base.rb +71 -0
  158. data/lib/active_scaffold/config/core.rb +219 -0
  159. data/lib/active_scaffold/config/create.rb +44 -0
  160. data/lib/active_scaffold/config/delete.rb +33 -0
  161. data/lib/active_scaffold/config/field_search.rb +76 -0
  162. data/lib/active_scaffold/config/form.rb +48 -0
  163. data/lib/active_scaffold/config/list.rb +196 -0
  164. data/lib/active_scaffold/config/mark.rb +35 -0
  165. data/lib/active_scaffold/config/nested.rb +42 -0
  166. data/lib/active_scaffold/config/search.rb +73 -0
  167. data/lib/active_scaffold/config/show.rb +32 -0
  168. data/lib/active_scaffold/config/subform.rb +35 -0
  169. data/lib/active_scaffold/config/update.rb +41 -0
  170. data/lib/active_scaffold/configurable.rb +29 -0
  171. data/lib/active_scaffold/constraints.rb +170 -0
  172. data/lib/active_scaffold/data_structures/action_columns.rb +140 -0
  173. data/lib/active_scaffold/data_structures/action_link.rb +179 -0
  174. data/lib/active_scaffold/data_structures/action_links.rb +185 -0
  175. data/lib/active_scaffold/data_structures/actions.rb +45 -0
  176. data/lib/active_scaffold/data_structures/bridge.rb +22 -0
  177. data/lib/active_scaffold/data_structures/column.rb +389 -0
  178. data/lib/active_scaffold/data_structures/columns.rb +75 -0
  179. data/lib/active_scaffold/data_structures/error_message.rb +24 -0
  180. data/lib/active_scaffold/data_structures/nested_info.rb +130 -0
  181. data/lib/active_scaffold/data_structures/set.rb +57 -0
  182. data/lib/active_scaffold/data_structures/sorting.rb +172 -0
  183. data/lib/active_scaffold/engine.rb +4 -0
  184. data/lib/active_scaffold/extensions/action_controller_rendering.rb +22 -0
  185. data/lib/active_scaffold/extensions/action_view_rendering.rb +115 -0
  186. data/lib/active_scaffold/extensions/active_record_offset.rb +12 -0
  187. data/lib/active_scaffold/extensions/array.rb +7 -0
  188. data/lib/active_scaffold/extensions/cache_association.rb +16 -0
  189. data/lib/active_scaffold/extensions/localize.rb +10 -0
  190. data/lib/active_scaffold/extensions/name_option_for_datetime.rb +12 -0
  191. data/lib/active_scaffold/extensions/nil_id_in_url_params.rb +7 -0
  192. data/lib/active_scaffold/extensions/paginator_extensions.rb +26 -0
  193. data/lib/active_scaffold/extensions/routing_mapper.rb +48 -0
  194. data/lib/active_scaffold/extensions/to_label.rb +8 -0
  195. data/lib/active_scaffold/extensions/unsaved_associated.rb +60 -0
  196. data/lib/active_scaffold/extensions/unsaved_record.rb +20 -0
  197. data/lib/active_scaffold/extensions/usa_state.rb +46 -0
  198. data/lib/active_scaffold/finder.rb +372 -0
  199. data/lib/active_scaffold/helpers/association_helpers.rb +48 -0
  200. data/lib/active_scaffold/helpers/controller_helpers.rb +88 -0
  201. data/lib/active_scaffold/helpers/form_column_helpers.rb +321 -0
  202. data/lib/active_scaffold/helpers/human_condition_helpers.rb +62 -0
  203. data/lib/active_scaffold/helpers/id_helpers.rb +127 -0
  204. data/lib/active_scaffold/helpers/list_column_helpers.rb +340 -0
  205. data/lib/active_scaffold/helpers/pagination_helpers.rb +55 -0
  206. data/lib/active_scaffold/helpers/search_column_helpers.rb +267 -0
  207. data/lib/active_scaffold/helpers/show_column_helpers.rb +50 -0
  208. data/lib/active_scaffold/helpers/view_helpers.rb +342 -0
  209. data/lib/active_scaffold/marked_model.rb +38 -0
  210. data/lib/active_scaffold/paginator.rb +136 -0
  211. data/lib/active_scaffold/responds_to_parent.rb +70 -0
  212. data/lib/active_scaffold/version.rb +9 -0
  213. data/lib/active_scaffold.rb +368 -0
  214. data/lib/active_scaffold_env.rb +11 -0
  215. data/lib/generators/active_scaffold/USAGE +29 -0
  216. data/lib/generators/active_scaffold/active_scaffold_generator.rb +20 -0
  217. data/lib/generators/active_scaffold_controller/USAGE +19 -0
  218. data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +29 -0
  219. data/lib/generators/active_scaffold_controller/templates/controller.rb +4 -0
  220. data/lib/generators/active_scaffold_controller/templates/helper.rb +2 -0
  221. data/public/blank.html +33 -0
  222. data/shoulda_macros/macros.rb +136 -0
  223. data/test/bridges/active_scaffold_dependent_protect_test.rb +34 -0
  224. data/test/bridges/bridge_test.rb +90 -0
  225. data/test/bridges/company.rb +81 -0
  226. data/test/bridges/paperclip_test.rb +68 -0
  227. data/test/bridges/tiny_mce_test.rb +27 -0
  228. data/test/bridges/unobtrusive_date_picker_test.rb +49 -0
  229. data/test/bridges/validation_reflection_test.rb +57 -0
  230. data/test/config/base_test.rb +15 -0
  231. data/test/config/core_test.rb +58 -0
  232. data/test/config/create_test.rb +58 -0
  233. data/test/config/delete_test.rb +33 -0
  234. data/test/config/field_search_test.rb +47 -0
  235. data/test/config/list_test.rb +129 -0
  236. data/test/config/nested_test.rb +62 -0
  237. data/test/config/search_test.rb +60 -0
  238. data/test/config/show_test.rb +43 -0
  239. data/test/config/subform_test.rb +17 -0
  240. data/test/config/update_test.rb +40 -0
  241. data/test/const_mocker.rb +36 -0
  242. data/test/data_structures/action_columns_test.rb +113 -0
  243. data/test/data_structures/action_link_test.rb +78 -0
  244. data/test/data_structures/action_links_test.rb +78 -0
  245. data/test/data_structures/actions_test.rb +25 -0
  246. data/test/data_structures/association_column_test.rb +42 -0
  247. data/test/data_structures/column_test.rb +185 -0
  248. data/test/data_structures/columns_test.rb +69 -0
  249. data/test/data_structures/error_message_test.rb +28 -0
  250. data/test/data_structures/set_test.rb +86 -0
  251. data/test/data_structures/sorting_test.rb +126 -0
  252. data/test/data_structures/standard_column_test.rb +24 -0
  253. data/test/data_structures/virtual_column_test.rb +23 -0
  254. data/test/extensions/active_record_test.rb +45 -0
  255. data/test/extensions/array_test.rb +12 -0
  256. data/test/helpers/form_column_helpers_test.rb +31 -0
  257. data/test/helpers/list_column_helpers_test.rb +42 -0
  258. data/test/helpers/pagination_helpers_test.rb +59 -0
  259. data/test/misc/active_record_permissions_test.rb +154 -0
  260. data/test/misc/attribute_params_test.rb +146 -0
  261. data/test/misc/configurable_test.rb +96 -0
  262. data/test/misc/constraints_test.rb +193 -0
  263. data/test/misc/finder_test.rb +92 -0
  264. data/test/misc/lang_test.rb +11 -0
  265. data/test/mock_app/app/controllers/application_controller.rb +10 -0
  266. data/test/mock_app/app/helpers/application_helper.rb +3 -0
  267. data/test/mock_app/config/boot.rb +110 -0
  268. data/test/mock_app/config/database.yml +16 -0
  269. data/test/mock_app/config/environment.rb +43 -0
  270. data/test/mock_app/config/environments/development.rb +17 -0
  271. data/test/mock_app/config/environments/production.rb +28 -0
  272. data/test/mock_app/config/environments/test.rb +28 -0
  273. data/test/mock_app/config/initializers/backtrace_silencers.rb +7 -0
  274. data/test/mock_app/config/initializers/inflections.rb +10 -0
  275. data/test/mock_app/config/initializers/mime_types.rb +5 -0
  276. data/test/mock_app/config/initializers/new_rails_defaults.rb +19 -0
  277. data/test/mock_app/config/initializers/session_store.rb +15 -0
  278. data/test/mock_app/config/locales/en.yml +5 -0
  279. data/test/mock_app/config/routes.rb +43 -0
  280. data/test/mock_app/db/test.sqlite3 +1 -0
  281. data/test/mock_app/public/blank.html +33 -0
  282. data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +2 -0
  283. data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
  284. data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
  285. data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
  286. data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
  287. data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
  288. data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
  289. data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
  290. data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
  291. data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +2 -0
  292. data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +532 -0
  293. data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +867 -0
  294. data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +117 -0
  295. data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +370 -0
  296. data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +2 -0
  297. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +35 -0
  298. data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +848 -0
  299. data/test/model_stub.rb +55 -0
  300. data/test/run_all.rb +8 -0
  301. data/test/test_helper.rb +39 -0
  302. data/vendor/assets/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  303. data/vendor/assets/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  304. data/vendor/assets/images/ui-bg_flat_10_000000_40x100.png +0 -0
  305. data/vendor/assets/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  306. data/vendor/assets/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  307. data/vendor/assets/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  308. data/vendor/assets/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  309. data/vendor/assets/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  310. data/vendor/assets/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  311. data/vendor/assets/images/ui-icons_222222_256x240.png +0 -0
  312. data/vendor/assets/images/ui-icons_228ef1_256x240.png +0 -0
  313. data/vendor/assets/images/ui-icons_ef8c08_256x240.png +0 -0
  314. data/vendor/assets/images/ui-icons_ffd27a_256x240.png +0 -0
  315. data/vendor/assets/images/ui-icons_ffffff_256x240.png +0 -0
  316. data/vendor/assets/javascripts/jquery-ui-timepicker-addon.js +1276 -0
  317. data/vendor/assets/stylesheets/jquery-ui.css +568 -0
  318. metadata +502 -0
@@ -0,0 +1,372 @@
1
+ module ActiveScaffold
2
+ module Finder
3
+ module ClassMethods
4
+ # Takes a collection of search terms (the tokens) and creates SQL that
5
+ # searches all specified ActiveScaffold columns. A row will match if each
6
+ # token is found in at least one of the columns.
7
+ def create_conditions_for_columns(tokens, columns, text_search = :full)
8
+ # if there aren't any columns, then just return a nil condition
9
+ return unless columns.length > 0
10
+ like_pattern = like_pattern(text_search)
11
+ tokens = [tokens] if tokens.is_a? String
12
+ obj = active_scaffold_config.model.new # for typecasting purposes
13
+
14
+ tokens.collect do |token|
15
+ pattern = like_pattern.sub('?', token)
16
+ columns.collect do |column|
17
+ if column.column.nil? or column.column[:type] == :string
18
+ column.search_sql.ilike(pattern)
19
+ else
20
+ begin
21
+ {column.search_sql => obj.send(:typecast_value, column.name, token)}
22
+ rescue Sequel::InvalidValue
23
+ end
24
+ end
25
+ end.compact.inject {|a,b| (a | b)}
26
+ end.inject {|a,b| (a & b)}
27
+ end
28
+
29
+ # Generates an SQL condition for the given ActiveScaffold column based on
30
+ # that column's database type (or form_ui ... for virtual columns?).
31
+ # TODO: this should reside on the column, not the controller
32
+ def condition_for_column(column, value, text_search = :full)
33
+ like_pattern = like_pattern(text_search)
34
+ if self.respond_to?("condition_for_#{column.name}_column")
35
+ return self.send("condition_for_#{column.name}_column", column, value, like_pattern)
36
+ end
37
+ return unless column and column.search_sql and not value.blank?
38
+ search_ui = column.search_ui || (column.column and column.column[:type])
39
+ begin
40
+ if search_ui && self.respond_to?("condition_for_#{search_ui}_type")
41
+ self.send("condition_for_#{search_ui}_type", column, value, like_pattern)
42
+ else
43
+ unless column.search_sql.instance_of? Proc
44
+ case search_ui
45
+ when :boolean, :checkbox
46
+ {column.search_sql => active_scaffold_config.model.db.send(:typecast_value_boolean, value)}
47
+ when :integer, :decimal, :float
48
+ condition_for_numeric(column, value)
49
+ when :string, :range
50
+ condition_for_range(column, value, like_pattern)
51
+ when :date, :time, :datetime, :timestamp
52
+ condition_for_datetime(column, value)
53
+ when :select, :multi_select, :country, :usa_state
54
+ {column.search_sql => Array(value)}
55
+ else
56
+ if column.column.nil? || column.column[:type] == :string
57
+ column.search_sql.ilike(like_pattern.sub('?', value))
58
+ else
59
+ {column.search_sql => active_scaffold_config.model.new.send(:typecast_value, column.name, value)}
60
+ end
61
+ end
62
+ else
63
+ column.search_sql.call(value)
64
+ end
65
+ end
66
+ rescue Exception => e
67
+ logger.error Time.now.to_s + "#{e.inspect} -- on the ActiveScaffold column :#{column.name}, search_ui = #{search_ui} in #{self.name}"
68
+ raise e
69
+ end
70
+ end
71
+
72
+ def condition_for_numeric(column, value)
73
+ if !value.is_a?(Hash)
74
+ {column.search_sql => condition_value_for_numeric(column, value)}
75
+ elsif value[:from].blank? or not ActiveScaffold::Finder::NumericComparators.include?(value[:opt])
76
+ nil
77
+ elsif value[:opt] == 'BETWEEN'
78
+ {column.search_sql => condition_value_for_numeric(column, value[:from])..condition_value_for_numeric(column, value[:to])}
79
+ else
80
+ Sequel::SQL::PlaceholderLiteralString.new("? #{value[:opt]} ?", [column.search_sql, condition_value_for_numeric(column, value[:from])])
81
+ end
82
+ end
83
+
84
+ def condition_for_range(column, value, like_pattern = nil)
85
+ if !value.is_a?(Hash)
86
+ if column.column.nil? || column.column[:type] == :string
87
+ column.search_sql.ilike(like_pattern.sub('?', value))
88
+ else
89
+ {column.search_sql => active_scaffold_config.model.new.send(:typecast_value, column.name, value)}
90
+ end
91
+ elsif ActiveScaffold::Finder::NullComparators.include?(value[:opt])
92
+ condition_for_null_type(column, value[:opt], like_pattern)
93
+ elsif value[:from].blank?
94
+ nil
95
+ elsif ActiveScaffold::Finder::StringComparators.values.include?(value[:opt])
96
+ column.search_sql.ilike(value[:opt].sub('?', value[:from]))
97
+ elsif value[:opt] == 'BETWEEN'
98
+ {column.search_sql => value[:from]..value[:to]}
99
+ elsif ActiveScaffold::Finder::NumericComparators.include?(value[:opt])
100
+ Sequel::SQL::PlaceholderLiteralString.new("? #{value[:opt]} ?", [column.search_sql, value[:from]])
101
+ else
102
+ nil
103
+ end
104
+ end
105
+
106
+ def condition_value_for_datetime(value, conversion = :to_time)
107
+ if value.is_a? Hash
108
+ Time.zone.local(*[:year, :month, :day, :hour, :minute, :second].collect {|part| value[part].to_i}) rescue nil
109
+ elsif value.respond_to?(:strftime)
110
+ value.send(conversion)
111
+ elsif conversion == :to_date
112
+ Date.strptime(value, I18n.t('date.formats.default')) rescue nil
113
+ else
114
+ parts = Date._parse(value)
115
+ time_parts = [[:hour, '%H'], [:min, '%M'], [:sec, '%S']].collect {|part, format_part| format_part if parts[part].present?}.compact
116
+ format = "#{I18n.t('date.formats.default')} #{time_parts.join(':')} #{'%z' if parts[:offset].present?}"
117
+ time = DateTime.strptime(value, format)
118
+ time = Time.zone.local_to_utc(time) unless parts[:offset]
119
+ time.in_time_zone.send(conversion) rescue nil
120
+ end unless value.nil? || value.blank?
121
+ end
122
+
123
+ def condition_value_for_numeric(column, value)
124
+ return value if value.nil?
125
+ value = i18n_number_to_native_format(value) if [:i18n_number, :currency].include?(column.options[:format])
126
+ case (column.search_ui || column.column[:type])
127
+ when :integer then value.to_i rescue value ? 1 : 0
128
+ when :float then value.to_f
129
+ when :decimal then active_scaffold_config.model.db.send(:typecast_value_decimal, value)
130
+ else
131
+ value
132
+ end
133
+ end
134
+
135
+ def i18n_number_to_native_format(value)
136
+ native = '.'
137
+ delimiter = I18n.t('number.format.delimiter')
138
+ separator = I18n.t('number.format.separator')
139
+ return value if value.blank? || !value.is_a?(String)
140
+ unless delimiter == native && !value.include?(separator) && value !~ /\.\d{3}$/
141
+ value.gsub(/[^0-9\-#{I18n.t('number.format.separator')}]/, '').gsub(I18n.t('number.format.separator'), native)
142
+ else
143
+ value
144
+ end
145
+ end
146
+
147
+ def condition_for_datetime(column, value, like_pattern = nil)
148
+ conversion = column.column[:type] == :date ? :to_date : :to_time
149
+ from_value = condition_value_for_datetime(value[:from], conversion)
150
+ to_value = condition_value_for_datetime(value[:to], conversion)
151
+
152
+ if from_value.nil? and to_value.nil?
153
+ nil
154
+ elsif !from_value
155
+ column.search_sql.sql_expr <= to_value.to_s(:db)
156
+ elsif !to_value
157
+ column.search_sql.sql_expr >= from_value.to_s(:db)
158
+ else
159
+ {column.search_sql => from_value.to_s(:db)..to_value.to_s(:db)}
160
+ end
161
+ end
162
+
163
+ def condition_for_record_select_type(column, value, like_pattern = nil)
164
+ {column.search_sql => value}
165
+ end
166
+
167
+ def condition_for_null_type(column, value, like_pattern = nil)
168
+ case value.to_sym
169
+ when :null
170
+ {column.search_sql => nil}
171
+ when :not_null
172
+ ~{column.search_sql => nil}
173
+ else
174
+ nil
175
+ end
176
+ end
177
+
178
+ def like_pattern(text_search)
179
+ case text_search
180
+ when :full then '%?%'
181
+ when :start then '?%'
182
+ when :end then '%?'
183
+ else '?'
184
+ end
185
+ end
186
+ end
187
+
188
+ NumericComparators = [
189
+ '=',
190
+ '>=',
191
+ '<=',
192
+ '>',
193
+ '<',
194
+ '!=',
195
+ 'BETWEEN'
196
+ ]
197
+ StringComparators = {
198
+ :contains => '%?%',
199
+ :begins_with => '?%',
200
+ :ends_with => '%?'
201
+ }
202
+ NullComparators = [
203
+ :null,
204
+ :not_null
205
+ ]
206
+
207
+
208
+
209
+ def self.included(klass)
210
+ klass.extend ClassMethods
211
+ end
212
+
213
+ protected
214
+
215
+ attr_writer :active_scaffold_conditions
216
+ def active_scaffold_conditions
217
+ @active_scaffold_conditions ||= []
218
+ end
219
+
220
+ attr_writer :active_scaffold_includes
221
+ def active_scaffold_includes
222
+ @active_scaffold_includes ||= []
223
+ end
224
+
225
+ attr_writer :active_scaffold_habtm_joins
226
+ def active_scaffold_habtm_joins
227
+ @active_scaffold_habtm_joins ||= []
228
+ end
229
+
230
+ def all_conditions
231
+ merge_conditions(
232
+ active_scaffold_conditions, # from the search modules
233
+ conditions_for_collection, # from the dev
234
+ conditions_from_params, # from the parameters (e.g. /users/list?first_name=Fred)
235
+ conditions_from_constraints, # from any constraints (embedded scaffolds)
236
+ active_scaffold_session_storage[:conditions] # embedding conditions (weaker constraints)
237
+ )
238
+ end
239
+
240
+ # returns a single record (the given id) but only if it's allowed for the specified action.
241
+ # accomplishes this by checking model.#{action}_authorized?
242
+ # TODO: this should reside on the model, not the controller
243
+ def find_if_allowed(id, crud_type, klass = beginning_of_chain)
244
+ record = klass[id]
245
+ raise ActiveScaffold::RecordNotAllowed, "#{klass} with id = #{id}" unless record.authorized_for?(:crud_type => crud_type.to_sym)
246
+ return record
247
+ end
248
+
249
+ # returns a hash with options to find records
250
+ # valid options may include:
251
+ # * :sorting - a Sorting DataStructure (basically an array of hashes of field => direction, e.g. [{:field1 => 'asc'}, {:field2 => 'desc'}]). please note that multi-column sorting has some limitations: if any column in a multi-field sort uses method-based sorting, it will be ignored. method sorting only works for single-column sorting.
252
+ # * :per_page
253
+ # * :page
254
+ def finder_options(options = {})
255
+ options.assert_valid_keys :sorting, :per_page, :page, :count_includes, :pagination, :select
256
+
257
+ search_conditions = all_conditions
258
+ full_includes = (active_scaffold_includes.blank? ? nil : active_scaffold_includes)
259
+
260
+ # create a general-use options array that's compatible with Rails finders
261
+ finder_options = { :order => options[:sorting].try(:clause),
262
+ :where => search_conditions,
263
+ :joins => joins_for_finder,
264
+ :includes => full_includes}
265
+
266
+ finder_options.merge! custom_finder_options
267
+ finder_options
268
+ end
269
+
270
+ # Returns a hash with options to count records, rejecting select and order options
271
+ # See finder_options for valid options
272
+ def count_options(find_options = {}, count_includes = nil)
273
+ count_includes ||= find_options[:includes] unless find_options[:where].nil?
274
+ options = find_options.reject{|k,v| [:select, :order].include? k}
275
+ options[:includes] = count_includes
276
+ options
277
+ end
278
+
279
+ # returns a Paginator::Page (not from ActiveRecord::Paginator) for the given parameters
280
+ # See finder_options for valid options
281
+ # TODO: this should reside on the model, not the controller
282
+ def find_page(options = {})
283
+ options[:per_page] ||= 999999999
284
+ options[:page] ||= 1
285
+
286
+ find_options = finder_options(options)
287
+ klass = beginning_of_chain
288
+
289
+ # NOTE: we must use :include in the count query, because some conditions may reference other tables
290
+ if options[:pagination] && options[:pagination] != :infinite
291
+ count_query = append_to_query(klass, count_options(find_options, options[:count_includes]))
292
+ count = count_query.count unless options[:pagination] == :infinite
293
+ end
294
+
295
+ # Converts count to an integer if ActiveRecord returned an OrderedHash
296
+ # that happens when find_options contains a :group key
297
+ count = count.length if count.is_a? ActiveSupport::OrderedHash
298
+
299
+ # we build the paginator differently for method- and sql-based sorting
300
+ if options[:sorting] and options[:sorting].sorts_by_method?
301
+ pager = ActiveScaffold::Paginator.new(count, options[:per_page]) do |offset, per_page|
302
+ sorted_collection = sort_collection_by_column(append_to_query(klass, find_options).all, *options[:sorting].first)
303
+ sorted_collection = sorted_collection.slice(offset, per_page) if options[:pagination]
304
+ sorted_collection
305
+ end
306
+ else
307
+ pager = ActiveScaffold::Paginator.new(count, options[:per_page]) do |offset, per_page|
308
+ find_options.merge!(:offset => offset, :limit => per_page) if options[:pagination]
309
+ append_to_query(klass, find_options).all
310
+ end
311
+ end
312
+ pager.page(options[:page])
313
+ end
314
+
315
+ def append_to_query(query, options)
316
+ options.assert_valid_keys :where, :select, :group, :order, :limit, :offset, :joins, :includes, :lock, :readonly, :from
317
+ offset = options.delete(:offset)
318
+ options.delete(:readonly)
319
+ options.reject{|k, v| v.blank?}.inject(query) do |query, (k, v)|
320
+ if k == :order
321
+ # default ordering of model has a higher priority than current queries ordering
322
+ # fix this by removing existing ordering from arel
323
+ query = query.unordered
324
+ query.send(:order, *v)
325
+ elsif k == :limit
326
+ val = [v]
327
+ val << offset if offset
328
+ query.send(:limit, *val)
329
+ elsif k == :includes
330
+ query.send(:eager, v)
331
+ elsif k == :joins
332
+ v.each do |j|
333
+ query = query.send(:join, *j)
334
+ end
335
+ query
336
+ elsif k == :lock
337
+ query.send(:lock_style, (v == true ? :update : v))
338
+ else
339
+ query.send(k, v)
340
+ end
341
+ end
342
+ end
343
+
344
+ def joins_for_finder
345
+ case joins_for_collection
346
+ when String
347
+ [ joins_for_collection ]
348
+ when Array
349
+ joins_for_collection
350
+ else
351
+ []
352
+ end + active_scaffold_habtm_joins
353
+ end
354
+
355
+ def merge_conditions(*conditions)
356
+ segments = conditions.collect {|c| c unless c.blank?}.compact
357
+ segments.inject {|a,b| (a & b)}
358
+ end
359
+
360
+ # TODO: this should reside on the column, not the controller
361
+ def sort_collection_by_column(collection, column, order)
362
+ sorter = column.sort[:method]
363
+ collection = collection.sort_by { |record|
364
+ value = (sorter.is_a? Proc) ? record.instance_eval(&sorter) : record.instance_eval(sorter)
365
+ value = '' if value.nil?
366
+ value
367
+ }
368
+ collection.reverse! if order.downcase == 'desc'
369
+ collection
370
+ end
371
+ end
372
+ end
@@ -0,0 +1,48 @@
1
+ module ActiveScaffold
2
+ module Helpers
3
+ module AssociationHelpers
4
+ # Provides a way to honor the :conditions on an association while searching the association's klass
5
+ def association_options_find(association, conditions = nil)
6
+ relation = association.associated_class.dataset
7
+ relation = relation.where(conditions) if conditions
8
+ relation = relation.where(association[:conditions]) if association[:conditions]
9
+ relation = relation.eager(association[:eager]) if association[:eager]
10
+ relation = relation.eager_graph(association[:eager_graph]) if association[:eager_graph]
11
+ relation.all
12
+ end
13
+
14
+ def association_options_count(association, conditions = nil)
15
+ relation = association.associated_class.dataset
16
+ relation = relation.where(conditions) if conditions
17
+ relation = relation.where(association[:conditions]) if association[:conditions]
18
+ relation.count
19
+ end
20
+
21
+ # returns options for the given association as a collection of [id, label] pairs intended for the +options_for_select+ helper.
22
+ def options_for_association(association, include_all = false)
23
+ available_records = association_options_find(association, include_all ? nil : options_for_association_conditions(association))
24
+ available_records ||= []
25
+ available_records.sort{|a,b| a.to_label <=> b.to_label}.collect { |model| [ model.to_label, model.id ] }
26
+ end
27
+
28
+ def options_for_association_count(association)
29
+ association_options_count(association, options_for_association_conditions(association))
30
+ end
31
+
32
+ # A useful override for customizing the records present in an association dropdown.
33
+ # Should work in both the subform and form_ui=>:select modes.
34
+ # Check association.name to specialize the conditions per-column.
35
+ def options_for_association_conditions(association)
36
+ return nil if association[:join_table]
37
+ case association[:type]
38
+ when :one_to_one, :one_to_many
39
+ # Find only orphaned objects
40
+ {association[:key] => nil}
41
+ when :many_to_one, :many_to_many
42
+ # Find all
43
+ nil
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,88 @@
1
+ module ActiveScaffold
2
+ module Helpers
3
+ module ControllerHelpers
4
+ def self.included(controller)
5
+ controller.class_eval { helper_method :params_for, :main_path_to_return, :render_parent?, :render_parent_options, :render_parent_action, :nested_singular_association?, :build_associated}
6
+ end
7
+
8
+ include ActiveScaffold::Helpers::IdHelpers
9
+
10
+ def params_for(options = {})
11
+ # :adapter and :position are one-use rendering arguments. they should not propagate.
12
+ # :sort, :sort_direction, and :page are arguments that stored in the session. they need not propagate.
13
+ # and wow. no we don't want to propagate :record.
14
+ # :commit is a special rails variable for form buttons
15
+ blacklist = [:adapter, :position, :sort, :sort_direction, :page, :record, :commit, :_method, :authenticity_token, :iframe]
16
+ unless @params_for
17
+ @params_for = {}
18
+ params.select { |key, value| blacklist.exclude? key.to_sym if key }.each {|key, value| @params_for[key.to_sym] = value.duplicable? ? value.clone : value}
19
+ @params_for[:controller] = '/' + @params_for[:controller].to_s unless @params_for[:controller].to_s.first(1) == '/' # for namespaced controllers
20
+ @params_for.delete(:id) if @params_for[:id].nil?
21
+ end
22
+ @params_for.merge(options)
23
+ end
24
+
25
+ # Parameters to generate url to the main page (override if the ActiveScaffold is used as a component on another controllers page)
26
+ def main_path_to_return
27
+ if params[:return_to]
28
+ params[:return_to]
29
+ else
30
+ parameters = {}
31
+ if params[:parent_controller]
32
+ parameters[:controller] = params[:parent_controller]
33
+ #parameters[:eid] = params[:parent_controller]
34
+ end
35
+ parameters.merge! nested.to_params if nested?
36
+ if params[:parent_sti]
37
+ parameters[:controller] = params[:parent_sti]
38
+ #parameters[:eid] = nil
39
+ end
40
+ parameters[:parent_column] = nil
41
+ parameters[:parent_id] = nil
42
+ parameters[:action] = "index"
43
+ parameters[:id] = nil
44
+ parameters[:associated_id] = nil
45
+ parameters[:utf8] = nil
46
+ params_for(parameters)
47
+ end
48
+ end
49
+
50
+ def nested_singular_association?
51
+ nested? && (nested.belongs_to? || nested.has_one?)
52
+ end
53
+
54
+ def render_parent?
55
+ nested_singular_association? || params[:parent_sti]
56
+ end
57
+
58
+ def render_parent_options
59
+ if nested_singular_association?
60
+ {:controller => nested.parent_scaffold.controller_path, :action => :row, :id => nested.parent_id}
61
+ elsif params[:parent_sti]
62
+ options = {:controller => params[:parent_sti], :action => render_parent_action(params[:parent_sti])}
63
+ if render_parent_action(params[:parent_sti]) == :index
64
+ options.merge(params.slice(:eid))
65
+ else
66
+ options.merge({:id => @record.id})
67
+ end
68
+ end
69
+ end
70
+
71
+ def render_parent_action(controller_path = nil)
72
+ begin
73
+ @parent_action = :row
74
+ parent_controller = "#{controller_path.to_s.camelize}Controller".constantize
75
+ @parent_action = :index if action_name == 'create' && parent_controller.active_scaffold_config.actions.include?(:create) && parent_controller.active_scaffold_config.create.refresh_list == true
76
+ @parent_action = :index if action_name == 'update' && parent_controller.active_scaffold_config.actions.include?(:update) && parent_controller.active_scaffold_config.update.refresh_list == true
77
+ @parent_action = :index if action_name == 'destroy' && parent_controller.active_scaffold_config.actions.include?(:delete) && parent_controller.active_scaffold_config.delete.refresh_list == true
78
+ rescue ActiveScaffold::ControllerNotFound
79
+ end if @parent_action.nil?
80
+ @parent_action
81
+ end
82
+
83
+ def build_associated(column, record)
84
+ column.association.associated_class.new
85
+ end
86
+ end
87
+ end
88
+ end