rails_admin-lbgraham 0.4.2

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 (416) hide show
  1. data/Gemfile +51 -0
  2. data/LICENSE.md +20 -0
  3. data/README.md +175 -0
  4. data/Rakefile +19 -0
  5. data/app/assets/images/rails_admin/aristo/images/bg_fallback.png +0 -0
  6. data/app/assets/images/rails_admin/aristo/images/icon_sprite.png +0 -0
  7. data/app/assets/images/rails_admin/aristo/images/progress_bar.gif +0 -0
  8. data/app/assets/images/rails_admin/aristo/images/slider_handles.png +0 -0
  9. data/app/assets/images/rails_admin/aristo/images/ui-icons_222222_256x240.png +0 -0
  10. data/app/assets/images/rails_admin/aristo/images/ui-icons_454545_256x240.png +0 -0
  11. data/app/assets/images/rails_admin/bullet_black.png +0 -0
  12. data/app/assets/images/rails_admin/bullet_white.png +0 -0
  13. data/app/assets/images/rails_admin/calendar.png +0 -0
  14. data/app/assets/images/rails_admin/clock.png +0 -0
  15. data/app/assets/images/rails_admin/colorpicker/colorpicker_background.png +0 -0
  16. data/app/assets/images/rails_admin/colorpicker/colorpicker_hex.png +0 -0
  17. data/app/assets/images/rails_admin/colorpicker/colorpicker_hsb_b.png +0 -0
  18. data/app/assets/images/rails_admin/colorpicker/colorpicker_hsb_h.png +0 -0
  19. data/app/assets/images/rails_admin/colorpicker/colorpicker_hsb_s.png +0 -0
  20. data/app/assets/images/rails_admin/colorpicker/colorpicker_indic.gif +0 -0
  21. data/app/assets/images/rails_admin/colorpicker/colorpicker_overlay.png +0 -0
  22. data/app/assets/images/rails_admin/colorpicker/colorpicker_rgb_b.png +0 -0
  23. data/app/assets/images/rails_admin/colorpicker/colorpicker_rgb_g.png +0 -0
  24. data/app/assets/images/rails_admin/colorpicker/colorpicker_rgb_r.png +0 -0
  25. data/app/assets/images/rails_admin/colorpicker/colorpicker_select.gif +0 -0
  26. data/app/assets/images/rails_admin/colorpicker/colorpicker_submit.png +0 -0
  27. data/app/assets/images/rails_admin/colorpicker/custom_background.png +0 -0
  28. data/app/assets/images/rails_admin/colorpicker/custom_hex.png +0 -0
  29. data/app/assets/images/rails_admin/colorpicker/custom_hsb_b.png +0 -0
  30. data/app/assets/images/rails_admin/colorpicker/custom_hsb_h.png +0 -0
  31. data/app/assets/images/rails_admin/colorpicker/custom_hsb_s.png +0 -0
  32. data/app/assets/images/rails_admin/colorpicker/custom_indic.gif +0 -0
  33. data/app/assets/images/rails_admin/colorpicker/custom_rgb_b.png +0 -0
  34. data/app/assets/images/rails_admin/colorpicker/custom_rgb_g.png +0 -0
  35. data/app/assets/images/rails_admin/colorpicker/custom_rgb_r.png +0 -0
  36. data/app/assets/images/rails_admin/colorpicker/custom_submit.png +0 -0
  37. data/app/assets/images/rails_admin/colorpicker/select.png +0 -0
  38. data/app/assets/images/rails_admin/colorpicker/select2.png +0 -0
  39. data/app/assets/images/rails_admin/colorpicker/slider.png +0 -0
  40. data/app/assets/images/rails_admin/logo.png +0 -0
  41. data/app/assets/images/rails_admin/magnifier.png +0 -0
  42. data/app/assets/images/rails_admin/multiselect/icon_sprite.png +0 -0
  43. data/app/assets/images/rails_admin/multiselect/ui-icon-circle-triangle-n-dark.png +0 -0
  44. data/app/assets/images/rails_admin/multiselect/ui-icon-circle-triangle-n-light.png +0 -0
  45. data/app/assets/images/rails_admin/multiselect/ui-icon-circle-triangle-s-dark.png +0 -0
  46. data/app/assets/images/rails_admin/multiselect/ui-icon-circle-triangle-s-light.png +0 -0
  47. data/app/assets/javascripts/rails_admin/custom/ui.js +12 -0
  48. data/app/assets/javascripts/rails_admin/jquery.colorpicker.js +484 -0
  49. data/app/assets/javascripts/rails_admin/jquery.pjax.js +743 -0
  50. data/app/assets/javascripts/rails_admin/jquery.ui.timepicker.js +1371 -0
  51. data/app/assets/javascripts/rails_admin/ra.datetimepicker.js +67 -0
  52. data/app/assets/javascripts/rails_admin/ra.filter-box.js +142 -0
  53. data/app/assets/javascripts/rails_admin/ra.filtering-multiselect.js +292 -0
  54. data/app/assets/javascripts/rails_admin/ra.filtering-select.js +190 -0
  55. data/app/assets/javascripts/rails_admin/ra.nested-form-hooks.coffee +41 -0
  56. data/app/assets/javascripts/rails_admin/ra.remote-form.js +151 -0
  57. data/app/assets/javascripts/rails_admin/ra.widgets.coffee +210 -0
  58. data/app/assets/javascripts/rails_admin/rails_admin.js.erb +28 -0
  59. data/app/assets/javascripts/rails_admin/themes/cerulean/ui.js +0 -0
  60. data/app/assets/javascripts/rails_admin/themes/default/ui.js +12 -0
  61. data/app/assets/javascripts/rails_admin/ui.js.coffee +66 -0
  62. data/app/assets/stylesheets/rails_admin/aristo/images/bg_fallback.png +0 -0
  63. data/app/assets/stylesheets/rails_admin/aristo/images/icon_sprite.png +0 -0
  64. data/app/assets/stylesheets/rails_admin/aristo/images/progress_bar.gif +0 -0
  65. data/app/assets/stylesheets/rails_admin/aristo/images/slider_handles.png +0 -0
  66. data/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_222222_256x240.png +0 -0
  67. data/app/assets/stylesheets/rails_admin/aristo/images/ui-icons_454545_256x240.png +0 -0
  68. data/app/assets/stylesheets/rails_admin/aristo/jquery-ui-1.8.7.custom.css.scss +733 -0
  69. data/app/assets/stylesheets/rails_admin/base/README.txt +2 -0
  70. data/app/assets/stylesheets/rails_admin/base/mixins.css.scss +1 -0
  71. data/app/assets/stylesheets/rails_admin/base/theming.css.scss +270 -0
  72. data/app/assets/stylesheets/rails_admin/base/variables.css.scss +1 -0
  73. data/app/assets/stylesheets/rails_admin/custom/mixins.css.scss +12 -0
  74. data/app/assets/stylesheets/rails_admin/custom/theming.css.scss +13 -0
  75. data/app/assets/stylesheets/rails_admin/custom/variables.css.scss +15 -0
  76. data/app/assets/stylesheets/rails_admin/imports.css.scss.erb +82 -0
  77. data/app/assets/stylesheets/rails_admin/jquery.colorpicker.css.scss +182 -0
  78. data/app/assets/stylesheets/rails_admin/jquery.ui.timepicker.css.scss +69 -0
  79. data/app/assets/stylesheets/rails_admin/ra.calendar-additions.css.scss +25 -0
  80. data/app/assets/stylesheets/rails_admin/ra.filtering-multiselect.css.scss +90 -0
  81. data/app/assets/stylesheets/rails_admin/ra.widgets.css.scss +8 -0
  82. data/app/assets/stylesheets/rails_admin/rails_admin.css +4 -0
  83. data/app/assets/stylesheets/rails_admin/themes/cerulean/mixins.css.scss +0 -0
  84. data/app/assets/stylesheets/rails_admin/themes/cerulean/theming.css.scss +97 -0
  85. data/app/assets/stylesheets/rails_admin/themes/cerulean/variables.css.scss +168 -0
  86. data/app/assets/stylesheets/rails_admin/themes/default/mixins.css.scss +8 -0
  87. data/app/assets/stylesheets/rails_admin/themes/default/theming.css.scss +11 -0
  88. data/app/assets/stylesheets/rails_admin/themes/default/variables.css.scss +12 -0
  89. data/app/controllers/rails_admin/application_controller.rb +84 -0
  90. data/app/controllers/rails_admin/main_controller.rb +153 -0
  91. data/app/helpers/rails_admin/application_helper.rb +147 -0
  92. data/app/helpers/rails_admin/form_builder.rb +117 -0
  93. data/app/helpers/rails_admin/main_helper.rb +36 -0
  94. data/app/views/kaminari/twitter-bootstrap/_gap.html.haml +2 -0
  95. data/app/views/kaminari/twitter-bootstrap/_next_page.html.haml +4 -0
  96. data/app/views/kaminari/twitter-bootstrap/_page.html.haml +4 -0
  97. data/app/views/kaminari/twitter-bootstrap/_paginator.html.haml +10 -0
  98. data/app/views/kaminari/twitter-bootstrap/_prev_page.html.haml +4 -0
  99. data/app/views/layouts/rails_admin/_secondary_navigation.html.haml +12 -0
  100. data/app/views/layouts/rails_admin/application.html.haml +27 -0
  101. data/app/views/layouts/rails_admin/pjax.html.haml +16 -0
  102. data/app/views/rails_admin/main/_dashboard_history.html.haml +20 -0
  103. data/app/views/rails_admin/main/_delete_notice.html.haml +19 -0
  104. data/app/views/rails_admin/main/_form_colorpicker.html.haml +1 -0
  105. data/app/views/rails_admin/main/_form_datetime.html.haml +1 -0
  106. data/app/views/rails_admin/main/_form_enumeration.html.haml +18 -0
  107. data/app/views/rails_admin/main/_form_field.html.haml +1 -0
  108. data/app/views/rails_admin/main/_form_file_upload.html.haml +13 -0
  109. data/app/views/rails_admin/main/_form_filtering_multiselect.html.haml +47 -0
  110. data/app/views/rails_admin/main/_form_filtering_select.html.haml +37 -0
  111. data/app/views/rails_admin/main/_form_nested_many.html.haml +14 -0
  112. data/app/views/rails_admin/main/_form_nested_one.html.haml +10 -0
  113. data/app/views/rails_admin/main/_form_polymorphic_association.html.haml +10 -0
  114. data/app/views/rails_admin/main/_form_text.html.haml +31 -0
  115. data/app/views/rails_admin/main/_submit_buttons.html.haml +15 -0
  116. data/app/views/rails_admin/main/bulk_delete.html.haml +11 -0
  117. data/app/views/rails_admin/main/dashboard.html.haml +35 -0
  118. data/app/views/rails_admin/main/delete.html.haml +18 -0
  119. data/app/views/rails_admin/main/edit.html.haml +2 -0
  120. data/app/views/rails_admin/main/export.html.haml +75 -0
  121. data/app/views/rails_admin/main/history.html.haml +49 -0
  122. data/app/views/rails_admin/main/index.html.haml +140 -0
  123. data/app/views/rails_admin/main/new.html.haml +2 -0
  124. data/app/views/rails_admin/main/show.html.haml +16 -0
  125. data/config/initializers/active_record_extensions.rb +19 -0
  126. data/config/initializers/devise_patch.rb +9 -0
  127. data/config/initializers/haml.rb +2 -0
  128. data/config/initializers/mongoid_extensions.rb +4 -0
  129. data/config/locales/rails_admin.en.yml +130 -0
  130. data/config/routes.rb +12 -0
  131. data/lib/generators/rails_admin/install_generator.rb +85 -0
  132. data/lib/generators/rails_admin/templates/drop.rb +18 -0
  133. data/lib/generators/rails_admin/templates/initializer.erb +100 -0
  134. data/lib/generators/rails_admin/templates/migration.rb +18 -0
  135. data/lib/generators/rails_admin/uninstall_generator.rb +22 -0
  136. data/lib/generators/rails_admin/utils.rb +30 -0
  137. data/lib/rails_admin.rb +34 -0
  138. data/lib/rails_admin/abstract_model.rb +128 -0
  139. data/lib/rails_admin/adapters/active_record.rb +296 -0
  140. data/lib/rails_admin/adapters/active_record/abstract_object.rb +32 -0
  141. data/lib/rails_admin/adapters/mongoid.rb +430 -0
  142. data/lib/rails_admin/adapters/mongoid/abstract_object.rb +43 -0
  143. data/lib/rails_admin/adapters/mongoid/extension.rb +45 -0
  144. data/lib/rails_admin/config.rb +333 -0
  145. data/lib/rails_admin/config/actions.rb +121 -0
  146. data/lib/rails_admin/config/actions/base.rb +132 -0
  147. data/lib/rails_admin/config/actions/bulk_delete.rb +55 -0
  148. data/lib/rails_admin/config/actions/dashboard.rb +52 -0
  149. data/lib/rails_admin/config/actions/delete.rb +56 -0
  150. data/lib/rails_admin/config/actions/edit.rb +55 -0
  151. data/lib/rails_admin/config/actions/export.rb +40 -0
  152. data/lib/rails_admin/config/actions/history_index.rb +38 -0
  153. data/lib/rails_admin/config/actions/history_show.rb +38 -0
  154. data/lib/rails_admin/config/actions/index.rb +85 -0
  155. data/lib/rails_admin/config/actions/new.rb +65 -0
  156. data/lib/rails_admin/config/actions/show.rb +34 -0
  157. data/lib/rails_admin/config/actions/show_in_app.rb +27 -0
  158. data/lib/rails_admin/config/configurable.rb +92 -0
  159. data/lib/rails_admin/config/fields.rb +87 -0
  160. data/lib/rails_admin/config/fields/association.rb +107 -0
  161. data/lib/rails_admin/config/fields/base.rb +320 -0
  162. data/lib/rails_admin/config/fields/factories/association.rb +32 -0
  163. data/lib/rails_admin/config/fields/factories/carrierwave.rb +31 -0
  164. data/lib/rails_admin/config/fields/factories/devise.rb +27 -0
  165. data/lib/rails_admin/config/fields/factories/dragonfly.rb +27 -0
  166. data/lib/rails_admin/config/fields/factories/enum.rb +11 -0
  167. data/lib/rails_admin/config/fields/factories/paperclip.rb +26 -0
  168. data/lib/rails_admin/config/fields/factories/password.rb +17 -0
  169. data/lib/rails_admin/config/fields/group.rb +78 -0
  170. data/lib/rails_admin/config/fields/types.rb +27 -0
  171. data/lib/rails_admin/config/fields/types/all.rb +25 -0
  172. data/lib/rails_admin/config/fields/types/belongs_to_association.rb +41 -0
  173. data/lib/rails_admin/config/fields/types/boolean.rb +38 -0
  174. data/lib/rails_admin/config/fields/types/bson_object_id.rb +45 -0
  175. data/lib/rails_admin/config/fields/types/carrierwave.rb +31 -0
  176. data/lib/rails_admin/config/fields/types/color.rb +37 -0
  177. data/lib/rails_admin/config/fields/types/date.rb +24 -0
  178. data/lib/rails_admin/config/fields/types/datetime.rb +164 -0
  179. data/lib/rails_admin/config/fields/types/decimal.rb +14 -0
  180. data/lib/rails_admin/config/fields/types/dragonfly.rb +41 -0
  181. data/lib/rails_admin/config/fields/types/enum.rb +39 -0
  182. data/lib/rails_admin/config/fields/types/file_upload.rb +65 -0
  183. data/lib/rails_admin/config/fields/types/float.rb +14 -0
  184. data/lib/rails_admin/config/fields/types/has_and_belongs_to_many_association.rb +14 -0
  185. data/lib/rails_admin/config/fields/types/has_many_association.rb +32 -0
  186. data/lib/rails_admin/config/fields/types/has_one_association.rb +39 -0
  187. data/lib/rails_admin/config/fields/types/hidden.rb +27 -0
  188. data/lib/rails_admin/config/fields/types/integer.rb +22 -0
  189. data/lib/rails_admin/config/fields/types/paperclip.rb +28 -0
  190. data/lib/rails_admin/config/fields/types/password.rb +39 -0
  191. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +80 -0
  192. data/lib/rails_admin/config/fields/types/serialized.rb +22 -0
  193. data/lib/rails_admin/config/fields/types/string.rb +43 -0
  194. data/lib/rails_admin/config/fields/types/text.rb +97 -0
  195. data/lib/rails_admin/config/fields/types/time.rb +36 -0
  196. data/lib/rails_admin/config/fields/types/timestamp.rb +18 -0
  197. data/lib/rails_admin/config/groupable.rb +18 -0
  198. data/lib/rails_admin/config/has_fields.rb +136 -0
  199. data/lib/rails_admin/config/has_groups.rb +23 -0
  200. data/lib/rails_admin/config/hideable.rb +28 -0
  201. data/lib/rails_admin/config/lazy_model.rb +21 -0
  202. data/lib/rails_admin/config/model.rb +109 -0
  203. data/lib/rails_admin/config/proxyable.rb +12 -0
  204. data/lib/rails_admin/config/proxyable/proxy.rb +43 -0
  205. data/lib/rails_admin/config/sections.rb +39 -0
  206. data/lib/rails_admin/config/sections/base.rb +46 -0
  207. data/lib/rails_admin/config/sections/create.rb +11 -0
  208. data/lib/rails_admin/config/sections/edit.rb +11 -0
  209. data/lib/rails_admin/config/sections/export.rb +11 -0
  210. data/lib/rails_admin/config/sections/list.rb +27 -0
  211. data/lib/rails_admin/config/sections/modal.rb +10 -0
  212. data/lib/rails_admin/config/sections/nested.rb +10 -0
  213. data/lib/rails_admin/config/sections/show.rb +10 -0
  214. data/lib/rails_admin/config/sections/update.rb +10 -0
  215. data/lib/rails_admin/engine.rb +27 -0
  216. data/lib/rails_admin/extension.rb +29 -0
  217. data/lib/rails_admin/extensions/cancan.rb +5 -0
  218. data/lib/rails_admin/extensions/cancan/authorization_adapter.rb +59 -0
  219. data/lib/rails_admin/extensions/history.rb +5 -0
  220. data/lib/rails_admin/extensions/history/auditing_adapter.rb +37 -0
  221. data/lib/rails_admin/extensions/history/history.rb +36 -0
  222. data/lib/rails_admin/extensions/paper_trail.rb +5 -0
  223. data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +93 -0
  224. data/lib/rails_admin/i18n_support.rb +43 -0
  225. data/lib/rails_admin/support/core_extensions.rb +44 -0
  226. data/lib/rails_admin/support/csv_converter.rb +105 -0
  227. data/lib/rails_admin/version.rb +18 -0
  228. data/lib/tasks/rails_admin.rake +48 -0
  229. data/spec/ci.sh +2 -0
  230. data/spec/controllers/rails_admin/application_controller_spec.rb +30 -0
  231. data/spec/controllers/rails_admin/main_controller_spec.rb +337 -0
  232. data/spec/dummy_app/Gemfile +48 -0
  233. data/spec/dummy_app/Rakefile +7 -0
  234. data/spec/dummy_app/app/active_record/abstract.rb +5 -0
  235. data/spec/dummy_app/app/active_record/another_field_test.rb +4 -0
  236. data/spec/dummy_app/app/active_record/ball.rb +9 -0
  237. data/spec/dummy_app/app/active_record/carrierwave_uploader.rb +53 -0
  238. data/spec/dummy_app/app/active_record/category.rb +5 -0
  239. data/spec/dummy_app/app/active_record/cms.rb +5 -0
  240. data/spec/dummy_app/app/active_record/cms/basic_page.rb +9 -0
  241. data/spec/dummy_app/app/active_record/cms/unscoped_page.rb +3 -0
  242. data/spec/dummy_app/app/active_record/comment.rb +5 -0
  243. data/spec/dummy_app/app/active_record/comment/confirmed.rb +3 -0
  244. data/spec/dummy_app/app/active_record/division.rb +15 -0
  245. data/spec/dummy_app/app/active_record/draft.rb +13 -0
  246. data/spec/dummy_app/app/active_record/fan.rb +7 -0
  247. data/spec/dummy_app/app/active_record/field_test.rb +19 -0
  248. data/spec/dummy_app/app/active_record/hardball.rb +2 -0
  249. data/spec/dummy_app/app/active_record/image.rb +6 -0
  250. data/spec/dummy_app/app/active_record/league.rb +12 -0
  251. data/spec/dummy_app/app/active_record/nested_field_test.rb +8 -0
  252. data/spec/dummy_app/app/active_record/player.rb +27 -0
  253. data/spec/dummy_app/app/active_record/team.rb +28 -0
  254. data/spec/dummy_app/app/active_record/user.rb +25 -0
  255. data/spec/dummy_app/app/assets/images/rails.png +0 -0
  256. data/spec/dummy_app/app/assets/javascripts/application.js +15 -0
  257. data/spec/dummy_app/app/assets/stylesheets/application.css +13 -0
  258. data/spec/dummy_app/app/controllers/application_controller.rb +3 -0
  259. data/spec/dummy_app/app/controllers/players_controller.rb +5 -0
  260. data/spec/dummy_app/app/locales/models.en.yml +20 -0
  261. data/spec/dummy_app/app/mongoid/another_field_test.rb +6 -0
  262. data/spec/dummy_app/app/mongoid/ball.rb +14 -0
  263. data/spec/dummy_app/app/mongoid/carrierwave_uploader.rb +53 -0
  264. data/spec/dummy_app/app/mongoid/category.rb +7 -0
  265. data/spec/dummy_app/app/mongoid/cms.rb +5 -0
  266. data/spec/dummy_app/app/mongoid/cms/basic_page.rb +12 -0
  267. data/spec/dummy_app/app/mongoid/cms/unscoped_page.rb +5 -0
  268. data/spec/dummy_app/app/mongoid/comment.rb +9 -0
  269. data/spec/dummy_app/app/mongoid/comment/confirmed.rb +3 -0
  270. data/spec/dummy_app/app/mongoid/division.rb +14 -0
  271. data/spec/dummy_app/app/mongoid/draft.rb +22 -0
  272. data/spec/dummy_app/app/mongoid/embed.rb +6 -0
  273. data/spec/dummy_app/app/mongoid/fan.rb +12 -0
  274. data/spec/dummy_app/app/mongoid/field_test.rb +57 -0
  275. data/spec/dummy_app/app/mongoid/hardball.rb +2 -0
  276. data/spec/dummy_app/app/mongoid/image.rb +9 -0
  277. data/spec/dummy_app/app/mongoid/league.rb +16 -0
  278. data/spec/dummy_app/app/mongoid/nested_field_test.rb +13 -0
  279. data/spec/dummy_app/app/mongoid/player.rb +41 -0
  280. data/spec/dummy_app/app/mongoid/team.rb +47 -0
  281. data/spec/dummy_app/app/mongoid/user.rb +61 -0
  282. data/spec/dummy_app/app/views/layouts/application.html.erb +14 -0
  283. data/spec/dummy_app/app/views/players/show.html.haml +1 -0
  284. data/spec/dummy_app/config.ru +4 -0
  285. data/spec/dummy_app/config/application.rb +69 -0
  286. data/spec/dummy_app/config/boot.rb +9 -0
  287. data/spec/dummy_app/config/database.yml +25 -0
  288. data/spec/dummy_app/config/environment.rb +5 -0
  289. data/spec/dummy_app/config/environments/development.rb +37 -0
  290. data/spec/dummy_app/config/environments/production.rb +67 -0
  291. data/spec/dummy_app/config/environments/test.rb +37 -0
  292. data/spec/dummy_app/config/initializers/backtrace_silencers.rb +7 -0
  293. data/spec/dummy_app/config/initializers/devise.rb +216 -0
  294. data/spec/dummy_app/config/initializers/dragonfly.rb +11 -0
  295. data/spec/dummy_app/config/initializers/inflections.rb +15 -0
  296. data/spec/dummy_app/config/initializers/mime_types.rb +5 -0
  297. data/spec/dummy_app/config/initializers/rails_admin.rb +8 -0
  298. data/spec/dummy_app/config/initializers/secret_token.rb +7 -0
  299. data/spec/dummy_app/config/initializers/session_patch.rb +16 -0
  300. data/spec/dummy_app/config/initializers/session_store.rb +8 -0
  301. data/spec/dummy_app/config/initializers/strong_parameters.rb +2 -0
  302. data/spec/dummy_app/config/initializers/wrap_parameters.rb +14 -0
  303. data/spec/dummy_app/config/locales/fr.yml +24 -0
  304. data/spec/dummy_app/config/mongoid.yml +22 -0
  305. data/spec/dummy_app/config/routes.rb +10 -0
  306. data/spec/dummy_app/db/migrate/00000000000001_create_divisions_migration.rb +13 -0
  307. data/spec/dummy_app/db/migrate/00000000000002_create_drafts_migration.rb +19 -0
  308. data/spec/dummy_app/db/migrate/00000000000003_create_leagues_migration.rb +12 -0
  309. data/spec/dummy_app/db/migrate/00000000000004_create_players_migration.rb +20 -0
  310. data/spec/dummy_app/db/migrate/00000000000005_create_teams_migration.rb +22 -0
  311. data/spec/dummy_app/db/migrate/00000000000006_devise_create_users.rb +49 -0
  312. data/spec/dummy_app/db/migrate/00000000000007_create_histories_table.rb +16 -0
  313. data/spec/dummy_app/db/migrate/00000000000008_create_fans_migration.rb +12 -0
  314. data/spec/dummy_app/db/migrate/00000000000009_create_fans_teams_migration.rb +11 -0
  315. data/spec/dummy_app/db/migrate/00000000000010_add_revenue_to_team_migration.rb +9 -0
  316. data/spec/dummy_app/db/migrate/00000000000011_add_suspended_to_player_migration.rb +9 -0
  317. data/spec/dummy_app/db/migrate/00000000000012_add_avatar_columns_to_user.rb +16 -0
  318. data/spec/dummy_app/db/migrate/00000000000013_add_roles_to_user.rb +9 -0
  319. data/spec/dummy_app/db/migrate/00000000000014_add_color_to_team_migration.rb +9 -0
  320. data/spec/dummy_app/db/migrate/20101223222233_create_rel_tests.rb +15 -0
  321. data/spec/dummy_app/db/migrate/20110103205808_create_comments.rb +15 -0
  322. data/spec/dummy_app/db/migrate/20110123042530_rename_histories_to_rails_admin_histories.rb +9 -0
  323. data/spec/dummy_app/db/migrate/20110224184303_create_field_tests.rb +22 -0
  324. data/spec/dummy_app/db/migrate/20110328193014_create_cms_basic_pages.rb +14 -0
  325. data/spec/dummy_app/db/migrate/20110329183136_remove_league_id_from_teams.rb +9 -0
  326. data/spec/dummy_app/db/migrate/20110607152842_add_format_to_field_test.rb +9 -0
  327. data/spec/dummy_app/db/migrate/20110714095433_create_balls.rb +12 -0
  328. data/spec/dummy_app/db/migrate/20110831090841_add_protected_field_and_restricted_field_to_field_tests.rb +6 -0
  329. data/spec/dummy_app/db/migrate/20110901131551_change_division_primary_key.rb +19 -0
  330. data/spec/dummy_app/db/migrate/20110901142530_rename_league_id_foreign_key_on_divisions.rb +5 -0
  331. data/spec/dummy_app/db/migrate/20110901150912_set_primary_key_not_null_for_divisions.rb +21 -0
  332. data/spec/dummy_app/db/migrate/20110901154834_change_length_for_rails_admin_histories.rb +9 -0
  333. data/spec/dummy_app/db/migrate/20111103174459_create_unscoped_pages.rb +9 -0
  334. data/spec/dummy_app/db/migrate/20111108143642_add_dragonfly_and_carrierwave_to_field_tests.rb +7 -0
  335. data/spec/dummy_app/db/migrate/20111115041025_add_type_to_balls.rb +5 -0
  336. data/spec/dummy_app/db/migrate/20111123092549_create_nested_field_tests.rb +10 -0
  337. data/spec/dummy_app/db/migrate/20111130075338_add_dragonfly_asset_name_to_field_tests.rb +5 -0
  338. data/spec/dummy_app/db/migrate/20111215083258_create_foo_bars.rb +8 -0
  339. data/spec/dummy_app/db/migrate/20120117151733_add_custom_field_to_teams.rb +5 -0
  340. data/spec/dummy_app/db/migrate/20120118122004_add_categories.rb +7 -0
  341. data/spec/dummy_app/db/migrate/20120319041705_drop_rel_tests.rb +15 -0
  342. data/spec/dummy_app/db/migrate/20120720075608_create_another_field_tests.rb +8 -0
  343. data/spec/dummy_app/db/migrate/20120928075608_create_images.rb +8 -0
  344. data/spec/dummy_app/db/seeds.rb +29 -0
  345. data/spec/dummy_app/doc/README_FOR_APP +2 -0
  346. data/spec/dummy_app/public/404.html +26 -0
  347. data/spec/dummy_app/public/422.html +26 -0
  348. data/spec/dummy_app/public/500.html +25 -0
  349. data/spec/dummy_app/public/favicon.ico +0 -0
  350. data/spec/dummy_app/public/robots.txt +5 -0
  351. data/spec/dummy_app/public/system/dragonfly/development/2011/11/24/10_36_27_888_Pensive_Parakeet.jpg +0 -0
  352. data/spec/dummy_app/public/system/dragonfly/development/2011/11/24/10_36_27_888_Pensive_Parakeet.jpg.meta +1 -0
  353. data/spec/dummy_app/public/system/dragonfly/development/2011/11/30/08_54_39_906_Costa_Rican_Frog.jpg +0 -0
  354. data/spec/dummy_app/public/system/dragonfly/development/2011/11/30/08_54_39_906_Costa_Rican_Frog.jpg.meta +1 -0
  355. data/spec/dummy_app/public/system/paperclip_assets/1/original/Boston City Flow.jpg +0 -0
  356. data/spec/dummy_app/public/system/paperclip_assets/1/thumb/Boston City Flow.jpg +0 -0
  357. data/spec/dummy_app/public/system/paperclip_assets/3/original/Costa Rican Frog.jpg +0 -0
  358. data/spec/dummy_app/public/system/paperclip_assets/3/thumb/Costa Rican Frog.jpg +0 -0
  359. data/spec/dummy_app/public/system/paperclip_assets/6/original/liste-electorale.pdf +0 -0
  360. data/spec/dummy_app/public/system/paperclip_assets/6/thumb/liste-electorale.pdf +148 -0
  361. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/3/Boston_City_Flow.jpg +0 -0
  362. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/3/thumb_Boston_City_Flow.jpg +0 -0
  363. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/4/Costa_Rican_Frog.jpg +0 -0
  364. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/4/thumb_Costa_Rican_Frog.jpg +0 -0
  365. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/6/Pensive_Parakeet.jpg +0 -0
  366. data/spec/dummy_app/public/uploads/field_test/carrierwave_asset/6/thumb_Pensive_Parakeet.jpg +0 -0
  367. data/spec/dummy_app/script/rails +6 -0
  368. data/spec/factories.rb +75 -0
  369. data/spec/helpers/rails_admin/application_helper_spec.rb +353 -0
  370. data/spec/helpers/rails_admin/form_builder_spec.rb +17 -0
  371. data/spec/integration/authorization/cancan_spec.rb +366 -0
  372. data/spec/integration/basic/bulk_action/rails_admin_basic_bulk_action_spec.rb +25 -0
  373. data/spec/integration/basic/bulk_destroy/rails_admin_basic_bulk_destroy_spec.rb +53 -0
  374. data/spec/integration/basic/create/rails_admin_basic_create_spec.rb +140 -0
  375. data/spec/integration/basic/create/rails_admin_namespaced_model_create_spec.rb +16 -0
  376. data/spec/integration/basic/delete/rails_admin_basic_delete_spec.rb +64 -0
  377. data/spec/integration/basic/destroy/rails_admin_basic_destroy_spec.rb +84 -0
  378. data/spec/integration/basic/edit/rails_admin_basic_edit_spec.rb +109 -0
  379. data/spec/integration/basic/export/rails_admin_basic_export_spec.rb +106 -0
  380. data/spec/integration/basic/list/rails_admin_basic_list_spec.rb +444 -0
  381. data/spec/integration/basic/new/rails_admin_basic_new_spec.rb +73 -0
  382. data/spec/integration/basic/new/rails_admin_namespaced_model_new_spec.rb +31 -0
  383. data/spec/integration/basic/show/rails_admin_basic_show_spec.rb +82 -0
  384. data/spec/integration/basic/update/rails_admin_basic_update_spec.rb +229 -0
  385. data/spec/integration/config/edit/rails_admin_config_edit_spec.rb +1026 -0
  386. data/spec/integration/config/list/rails_admin_config_list_spec.rb +441 -0
  387. data/spec/integration/config/show/rails_admin_config_show_spec.rb +331 -0
  388. data/spec/integration/history/rails_admin_history_spec.rb +88 -0
  389. data/spec/integration/rails_admin_spec.rb +150 -0
  390. data/spec/integration/relation_spec.rb +35 -0
  391. data/spec/orm/active_record.rb +42 -0
  392. data/spec/orm/mongoid.rb +21 -0
  393. data/spec/rails_admin/abstract_model_spec.rb +75 -0
  394. data/spec/rails_admin/active_record_extension_spec.rb +16 -0
  395. data/spec/rails_admin/adapters/active_record/abstract_object_spec.rb +132 -0
  396. data/spec/rails_admin/adapters/active_record_spec.rb +409 -0
  397. data/spec/rails_admin/adapters/mongoid/abstract_object_spec.rb +31 -0
  398. data/spec/rails_admin/adapters/mongoid_spec.rb +776 -0
  399. data/spec/rails_admin/config/actions/base_spec.rb +32 -0
  400. data/spec/rails_admin/config/actions_spec.rb +180 -0
  401. data/spec/rails_admin/config/fields/base_spec.rb +421 -0
  402. data/spec/rails_admin/config/fields/date_spec.rb +74 -0
  403. data/spec/rails_admin/config/fields/datetime_spec.rb +55 -0
  404. data/spec/rails_admin/config/fields/file_upload_spec.rb +21 -0
  405. data/spec/rails_admin/config/fields/time_spec.rb +39 -0
  406. data/spec/rails_admin/config/fields/timestamp_spec.rb +20 -0
  407. data/spec/rails_admin/config/fields/types/datetime_spec.rb +18 -0
  408. data/spec/rails_admin/config/fields_spec.rb +15 -0
  409. data/spec/rails_admin/config/has_fields_spec.rb +30 -0
  410. data/spec/rails_admin/config/lazy_model_spec.rb +29 -0
  411. data/spec/rails_admin/config/model_spec.rb +75 -0
  412. data/spec/rails_admin/config/sections_spec.rb +123 -0
  413. data/spec/rails_admin/config_spec.rb +277 -0
  414. data/spec/rails_admin/support/csv_converter_spec.rb +16 -0
  415. data/spec/spec_helper.rb +84 -0
  416. metadata +868 -0
@@ -0,0 +1,296 @@
1
+ require 'active_record'
2
+ require 'rails_admin/adapters/active_record/abstract_object'
3
+
4
+ module RailsAdmin
5
+ module Adapters
6
+ module ActiveRecord
7
+ DISABLED_COLUMN_TYPES = [:tsvector, :blob, :binary, :spatial, :hstore, :geometry]
8
+ DISABLED_COLUMN_MATCHERS = [/_array$/]
9
+
10
+ def ar_adapter
11
+ Rails.configuration.database_configuration[Rails.env]['adapter']
12
+ end
13
+
14
+ def like_operator
15
+ ar_adapter == "postgresql" ? 'ILIKE' : 'LIKE'
16
+ end
17
+
18
+ def new(params = {})
19
+ AbstractObject.new(model.new(params))
20
+ end
21
+
22
+ def get(id)
23
+ if object = model.where(model.primary_key => id).first
24
+ AbstractObject.new object
25
+ else
26
+ nil
27
+ end
28
+ end
29
+
30
+ def scoped
31
+ model.scoped
32
+ end
33
+
34
+ def first(options = {}, scope = nil)
35
+ all(options, scope).first
36
+ end
37
+
38
+ def all(options = {}, scope = nil)
39
+ scope ||= self.scoped
40
+ scope = scope.includes(options[:include]) if options[:include]
41
+ scope = scope.limit(options[:limit]) if options[:limit]
42
+ scope = scope.where(model.primary_key => options[:bulk_ids]) if options[:bulk_ids]
43
+ scope = scope.where(query_conditions(options[:query])) if options[:query]
44
+ scope = scope.where(filter_conditions(options[:filters])) if options[:filters]
45
+ if options[:page] && options[:per]
46
+ scope = scope.send(Kaminari.config.page_method_name, options[:page]).per(options[:per])
47
+ end
48
+ scope = scope.reorder("#{options[:sort]} #{options[:sort_reverse] ? 'asc' : 'desc'}") if options[:sort]
49
+ scope
50
+ end
51
+
52
+ def count(options = {}, scope = nil)
53
+ all(options.merge({:limit => false, :page => false}), scope).count
54
+ end
55
+
56
+ def destroy(objects)
57
+ Array.wrap(objects).each &:destroy
58
+ end
59
+
60
+ def primary_key
61
+ model.primary_key
62
+ end
63
+
64
+ def associations
65
+ model.reflect_on_all_associations.map do |association|
66
+ {
67
+ :name => association.name.to_sym,
68
+ :pretty_name => association.name.to_s.tr('_', ' ').capitalize,
69
+ :type => association.macro,
70
+ :model_proc => Proc.new { association_model_lookup(association) },
71
+ :primary_key_proc => Proc.new { association_primary_key_lookup(association) },
72
+ :foreign_key => association_foreign_key_lookup(association),
73
+ :foreign_type => association_foreign_type_lookup(association),
74
+ :as => association_as_lookup(association),
75
+ :polymorphic => association_polymorphic_lookup(association),
76
+ :inverse_of => association_inverse_of_lookup(association),
77
+ :read_only => association_read_only_lookup(association),
78
+ :nested_form => association_nested_attributes_options_lookup(association)
79
+ }
80
+ end
81
+ end
82
+
83
+ def properties
84
+ columns = model.columns.reject do |c|
85
+ c.type.blank? || DISABLED_COLUMN_TYPES.include?(c.type.to_sym) || DISABLED_COLUMN_MATCHERS.any? {|matcher| matcher.match(c.type.to_s)}
86
+ end
87
+ columns.map do |property|
88
+ {
89
+ :name => property.name.to_sym,
90
+ :pretty_name => property.name.to_s.tr('_', ' ').capitalize,
91
+ :length => property.limit,
92
+ :nullable? => property.null,
93
+ :serial? => property.primary,
94
+ }.merge(type_lookup(property))
95
+ end
96
+ end
97
+
98
+ def table_name
99
+ model.table_name
100
+ end
101
+
102
+ def encoding
103
+ Rails.configuration.database_configuration[Rails.env]['encoding']
104
+ end
105
+
106
+ def embedded?
107
+ false
108
+ end
109
+
110
+ def adapter_supports_joins?
111
+ true
112
+ end
113
+
114
+ private
115
+
116
+ def query_conditions(query, fields = config.list.fields.select(&:queryable?))
117
+ statements = []
118
+ values = []
119
+
120
+ fields.each do |field|
121
+ field.searchable_columns.flatten.each do |column_infos|
122
+ statement, value1, value2 = build_statement(column_infos[:column], column_infos[:type], query, field.search_operator)
123
+ statements << statement if statement
124
+ values << value1 unless value1.nil?
125
+ values << value2 unless value2.nil?
126
+ end
127
+ end
128
+
129
+ [statements.join(' OR '), *values]
130
+ end
131
+
132
+ # filters example => {"string_field"=>{"0055"=>{"o"=>"like", "v"=>"test_value"}}, ...}
133
+ # "0055" is the filter index, no use here. o is the operator, v the value
134
+ def filter_conditions(filters, fields = config.list.fields.select(&:filterable?))
135
+ statements = []
136
+ values = []
137
+
138
+ filters.each_pair do |field_name, filters_dump|
139
+ filters_dump.each do |filter_index, filter_dump|
140
+ field_statements = []
141
+ fields.find{|f| f.name.to_s == field_name}.searchable_columns.each do |column_infos|
142
+ statement, value1, value2 = build_statement(column_infos[:column], column_infos[:type], filter_dump[:v], (filter_dump[:o] || 'default'))
143
+ field_statements << statement if statement.present?
144
+ values << value1 unless value1.nil?
145
+ values << value2 unless value2.nil?
146
+ end
147
+ statements << "(#{field_statements.join(' OR ')})" unless field_statements.empty?
148
+ end
149
+ end
150
+
151
+ [statements.join(' AND '), *values]
152
+ end
153
+
154
+ def build_statement(column, type, value, operator)
155
+ # this operator/value has been discarded (but kept in the dom to override the one stored in the various links of the page)
156
+ return if operator == '_discard' || value == '_discard'
157
+
158
+ # filtering data with unary operator, not type dependent
159
+ if operator == '_blank' || value == '_blank'
160
+ return ["(#{column} IS NULL OR #{column} = '')"]
161
+ elsif operator == '_present' || value == '_present'
162
+ return ["(#{column} IS NOT NULL AND #{column} != '')"]
163
+ elsif operator == '_null' || value == '_null'
164
+ return ["(#{column} IS NULL)"]
165
+ elsif operator == '_not_null' || value == '_not_null'
166
+ return ["(#{column} IS NOT NULL)"]
167
+ elsif operator == '_empty' || value == '_empty'
168
+ return ["(#{column} = '')"]
169
+ elsif operator == '_not_empty' || value == '_not_empty'
170
+ return ["(#{column} != '')"]
171
+ end
172
+
173
+ # now we go type specific
174
+ case type
175
+ when :boolean
176
+ return ["(#{column} IS NULL OR #{column} = ?)", false] if ['false', 'f', '0'].include?(value)
177
+ return ["(#{column} = ?)", true] if ['true', 't', '1'].include?(value)
178
+ when :decimal, :float
179
+ return if value.blank?
180
+ ["(#{column} = ?)", value.to_f] if value.to_f.to_s == value || value.to_i.to_s == value
181
+ when :integer
182
+ case value
183
+ when Array then
184
+ val, range_begin, range_end = *value.map{|v| v.blank? ? nil : (v == v.to_i.to_s) ? v.to_i : nil}
185
+ case operator
186
+ when 'between'
187
+ if range_begin && range_end
188
+ ["(#{column} BETWEEN ? AND ?)", range_begin, range_end]
189
+ elsif range_begin
190
+ ["(#{column} >= ?)", range_begin]
191
+ elsif range_end
192
+ ["(#{column} <= ?)", range_end]
193
+ end
194
+ else
195
+ ["(#{column} = ?)", val] if val
196
+ end
197
+ else
198
+ s = value.to_s
199
+ return s =~ /^[\-]?\d+$/ ? ["(#{column} = ?)", s.to_i] : nil
200
+ end
201
+ when :belongs_to_association
202
+ return if value.blank?
203
+ ["(#{column} = ?)", value.to_i] if value.to_i.to_s == value
204
+ when :string, :text
205
+ return if value.blank?
206
+ value = case operator
207
+ when 'default', 'like'
208
+ "%#{value.downcase}%"
209
+ when 'starts_with'
210
+ "#{value.downcase}%"
211
+ when 'ends_with'
212
+ "%#{value.downcase}"
213
+ when 'is', '='
214
+ "#{value.downcase}"
215
+ else
216
+ return
217
+ end
218
+ ["(LOWER(#{column}) #{like_operator} ?)", value]
219
+ when :date
220
+ start_date, end_date = get_filtering_duration(operator, value)
221
+
222
+ if start_date && end_date
223
+ ["(#{column} BETWEEN ? AND ?)", start_date, end_date]
224
+ elsif start_date
225
+ ["(#{column} >= ?)", start_date]
226
+ elsif end_date
227
+ ["(#{column} <= ?)", end_date]
228
+ end
229
+ when :datetime, :timestamp
230
+ start_date, end_date = get_filtering_duration(operator, value)
231
+
232
+ if start_date && end_date
233
+ ["(#{column} BETWEEN ? AND ?)", start_date.to_time.beginning_of_day, end_date.to_time.end_of_day]
234
+ elsif start_date
235
+ ["(#{column} >= ?)", start_date.to_time.beginning_of_day]
236
+ elsif end_date
237
+ ["(#{column} <= ?)", end_date.to_time.end_of_day]
238
+ end
239
+ when :enum
240
+ return if value.blank?
241
+ ["(#{column} IN (?))", Array.wrap(value)]
242
+ end
243
+ end
244
+
245
+ def type_lookup(property)
246
+ if model.serialized_attributes[property.name.to_s]
247
+ {:type => :serialized}
248
+ else
249
+ {:type => property.type}
250
+ end
251
+ end
252
+
253
+ def association_model_lookup(association)
254
+ if association.options[:polymorphic]
255
+ RailsAdmin::AbstractModel.polymorphic_parents(:active_record, self.model.model_name, association.name) || []
256
+ else
257
+ association.klass
258
+ end
259
+ end
260
+
261
+ def association_foreign_type_lookup(association)
262
+ if association.options[:polymorphic]
263
+ association.options[:foreign_type].try(:to_sym) || :"#{association.name}_type"
264
+ end
265
+ end
266
+
267
+ def association_nested_attributes_options_lookup(association)
268
+ model.nested_attributes_options.try { |o| o[association.name.to_sym] }
269
+ end
270
+
271
+ def association_as_lookup(association)
272
+ association.options[:as].try :to_sym
273
+ end
274
+
275
+ def association_polymorphic_lookup(association)
276
+ !!association.options[:polymorphic]
277
+ end
278
+
279
+ def association_primary_key_lookup(association)
280
+ association.options[:primary_key] || association.klass.primary_key
281
+ end
282
+
283
+ def association_inverse_of_lookup(association)
284
+ association.options[:inverse_of].try :to_sym
285
+ end
286
+
287
+ def association_read_only_lookup(association)
288
+ association.options[:readonly]
289
+ end
290
+
291
+ def association_foreign_key_lookup(association)
292
+ association.foreign_key.to_sym
293
+ end
294
+ end
295
+ end
296
+ end
@@ -0,0 +1,32 @@
1
+ module RailsAdmin
2
+ module Adapters
3
+ module ActiveRecord
4
+ class AbstractObject
5
+ # undef almost all of this class's methods so it will pass almost
6
+ # everything through to its delegate using method_missing (below).
7
+ instance_methods.each { |m| undef_method m unless m.to_s =~ /(^__|^send$|^object_id$)/ }
8
+ # ^^^^^
9
+ # the unnecessary "to_s" above is a workaround for meta_where, see
10
+ # https://github.com/sferik/rails_admin/issues/374
11
+
12
+ attr_accessor :object
13
+
14
+ def initialize(object)
15
+ self.object = object
16
+ end
17
+
18
+ def set_attributes(attributes, role = nil)
19
+ object.assign_attributes(attributes, :as => role)
20
+ end
21
+
22
+ def save(options = { :validate => true })
23
+ object.save(options)
24
+ end
25
+
26
+ def method_missing(name, *args, &block)
27
+ self.object.send(name, *args, &block)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,430 @@
1
+ require 'mongoid'
2
+ require 'rails_admin/config/sections/list'
3
+ require 'rails_admin/adapters/mongoid/abstract_object'
4
+
5
+ module RailsAdmin
6
+ module Adapters
7
+ module Mongoid
8
+ STRING_TYPE_COLUMN_NAMES = [:name, :title, :subject]
9
+ DISABLED_COLUMN_TYPES = ['Range']
10
+ ObjectId = (::Mongoid::VERSION >= '3' ? ::Moped::BSON::ObjectId : ::BSON::ObjectId)
11
+
12
+ def new(params = {})
13
+ AbstractObject.new(model.new)
14
+ end
15
+
16
+ def get(id)
17
+ begin
18
+ AbstractObject.new(model.find(id))
19
+ rescue => e
20
+ if ['BSON::InvalidObjectId', 'Mongoid::Errors::DocumentNotFound',
21
+ 'Mongoid::Errors::InvalidFind', 'Moped::Errors::InvalidObjectId'].include? e.class.to_s
22
+ nil
23
+ else
24
+ raise e
25
+ end
26
+ end
27
+ end
28
+
29
+ def scoped
30
+ model.scoped
31
+ end
32
+
33
+ def first(options = {},scope=nil)
34
+ all(options, scope).first
35
+ end
36
+
37
+ def all(options = {},scope=nil)
38
+ scope ||= self.scoped
39
+ scope = scope.includes(*options[:include]) if options[:include]
40
+ scope = scope.limit(options[:limit]) if options[:limit]
41
+ scope = scope.any_in(:_id => options[:bulk_ids]) if options[:bulk_ids]
42
+ scope = scope.where(query_conditions(options[:query])) if options[:query]
43
+ scope = scope.where(filter_conditions(options[:filters])) if options[:filters]
44
+ if options[:page] && options[:per]
45
+ scope = scope.send(Kaminari.config.page_method_name, options[:page]).per(options[:per])
46
+ end
47
+ scope = sort_by(options, scope) if options[:sort]
48
+ scope
49
+ end
50
+
51
+ def count(options = {},scope=nil)
52
+ all(options.merge({:limit => false, :page => false}), scope).count
53
+ end
54
+
55
+ def destroy(objects)
56
+ Array.wrap(objects).each &:destroy
57
+ end
58
+
59
+ def primary_key
60
+ '_id'
61
+ end
62
+
63
+ def associations
64
+ model.associations.values.map do |association|
65
+ {
66
+ :name => association.name.to_sym,
67
+ :pretty_name => association.name.to_s.tr('_', ' ').capitalize,
68
+ :type => association_type_lookup(association.macro),
69
+ :model_proc => Proc.new { association_model_proc_lookup(association) },
70
+ :primary_key_proc => Proc.new { association_primary_key_lookup(association) },
71
+ :foreign_key => association_foreign_key_lookup(association),
72
+ :foreign_type => association_foreign_type_lookup(association),
73
+ :foreign_inverse_of => association_foreign_inverse_of_lookup(association),
74
+ :as => association_as_lookup(association),
75
+ :polymorphic => association_polymorphic_lookup(association),
76
+ :inverse_of => association_inverse_of_lookup(association),
77
+ :read_only => nil,
78
+ :nested_form => association_nested_attributes_options_lookup(association)
79
+ }
80
+ end
81
+ end
82
+
83
+ def properties
84
+ fields = model.fields.reject{|name, field| DISABLED_COLUMN_TYPES.include?(field.type.to_s) }
85
+ fields.map do |name,field|
86
+ {
87
+ :name => field.name.to_sym,
88
+ :length => nil,
89
+ :pretty_name => field.name.to_s.gsub('_', ' ').strip.capitalize,
90
+ :nullable? => true,
91
+ :serial? => false,
92
+ }.merge(type_lookup(name, field))
93
+ end
94
+ end
95
+
96
+ def table_name
97
+ model.collection_name.to_s
98
+ end
99
+
100
+ def encoding
101
+ 'UTF-8'
102
+ end
103
+
104
+ def embedded?
105
+ @embedded ||= !!model.associations.values.find{|a| a.macro.to_sym == :embedded_in }
106
+ end
107
+
108
+ def object_id_from_string(str)
109
+ ObjectId.from_string(str)
110
+ end
111
+
112
+ def adapter_supports_joins?
113
+ false
114
+ end
115
+
116
+ private
117
+
118
+ def query_conditions(query, fields = config.list.fields.select(&:queryable?))
119
+ statements = []
120
+
121
+ fields.each do |field|
122
+ conditions_per_collection = {}
123
+ field.searchable_columns.flatten.each do |column_infos|
124
+ collection_name, column_name = parse_collection_name(column_infos[:column])
125
+ statement = build_statement(column_name, column_infos[:type], query, field.search_operator)
126
+ if statement
127
+ conditions_per_collection[collection_name] ||= []
128
+ conditions_per_collection[collection_name] << statement
129
+ end
130
+ end
131
+ statements.concat make_condition_for_current_collection(field, conditions_per_collection)
132
+ end
133
+
134
+ if statements.any?
135
+ { '$or' => statements }
136
+ else
137
+ {}
138
+ end
139
+ end
140
+
141
+ # filters example => {"string_field"=>{"0055"=>{"o"=>"like", "v"=>"test_value"}}, ...}
142
+ # "0055" is the filter index, no use here. o is the operator, v the value
143
+ def filter_conditions(filters, fields = config.list.fields.select(&:filterable?))
144
+ statements = []
145
+
146
+ filters.each_pair do |field_name, filters_dump|
147
+ filters_dump.each do |filter_index, filter_dump|
148
+ conditions_per_collection = {}
149
+ field = fields.find{|f| f.name.to_s == field_name}
150
+ next unless field
151
+ field.searchable_columns.each do |column_infos|
152
+ collection_name, column_name = parse_collection_name(column_infos[:column])
153
+ statement = build_statement(column_name, column_infos[:type], filter_dump[:v], (filter_dump[:o] || 'default'))
154
+ if statement
155
+ conditions_per_collection[collection_name] ||= []
156
+ conditions_per_collection[collection_name] << statement
157
+ end
158
+ end
159
+ if conditions_per_collection.any?
160
+ field_statements = make_condition_for_current_collection(field, conditions_per_collection)
161
+ if field_statements.length > 1
162
+ statements << { '$or' => field_statements }
163
+ else
164
+ statements << field_statements.first
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ if statements.any?
171
+ { '$and' => statements }
172
+ else
173
+ {}
174
+ end
175
+ end
176
+
177
+ def build_statement(column, type, value, operator)
178
+ # this operator/value has been discarded (but kept in the dom to override the one stored in the various links of the page)
179
+ return if operator == '_discard' || value == '_discard'
180
+
181
+ # filtering data with unary operator, not type dependent
182
+ if operator == '_blank' || value == '_blank'
183
+ return { column => {'$in' => [nil, '']} }
184
+ elsif operator == '_present' || value == '_present'
185
+ return { column => {'$nin' => [nil, '']} }
186
+ elsif operator == '_null' || value == '_null'
187
+ return { column => nil }
188
+ elsif operator == '_not_null' || value == '_not_null'
189
+ return { column => {'$ne' => nil} }
190
+ elsif operator == '_empty' || value == '_empty'
191
+ return { column => '' }
192
+ elsif operator == '_not_empty' || value == '_not_empty'
193
+ return { column => {'$ne' => ''} }
194
+ end
195
+ # now we go type specific
196
+ case type
197
+ when :boolean
198
+ return { column => false } if ['false', 'f', '0'].include?(value)
199
+ return { column => true } if ['true', 't', '1'].include?(value)
200
+ when :integer
201
+ case value
202
+ when Array then
203
+ val, range_begin, range_end = *value.map{|v| v.blank? ? nil : (v == v.to_i.to_s) ? v.to_i : nil}
204
+ if range_begin && range_end
205
+ { column => {'$gte' => range_begin, '$lte' => range_end} }
206
+ elsif range_begin
207
+ { column => {'$gte' => range_begin} }
208
+ elsif range_end
209
+ { column => {'$lte' => range_end} }
210
+ elsif val
211
+ { column => val }
212
+ end
213
+ else
214
+ s = value.to_s
215
+ return s =~ /^[\-]?\d+$/ ? { column => s.to_i } : nil
216
+ end
217
+ when :string, :text
218
+ return if value.blank?
219
+ value = case operator
220
+ when 'default', 'like'
221
+ Regexp.compile(Regexp.escape(value), Regexp::IGNORECASE)
222
+ when 'starts_with'
223
+ Regexp.compile("^#{Regexp.escape(value)}", Regexp::IGNORECASE)
224
+ when 'ends_with'
225
+ Regexp.compile("#{Regexp.escape(value)}$", Regexp::IGNORECASE)
226
+ when 'is', '='
227
+ value.to_s
228
+ else
229
+ return
230
+ end
231
+ { column => value }
232
+ when :date
233
+ start_date, end_date = get_filtering_duration(operator, value)
234
+
235
+ if start_date && end_date
236
+ { column => { '$gte' => start_date, '$lte' => end_date } }
237
+ elsif start_date
238
+ { column => { '$gte' => start_date } }
239
+ elsif end_date
240
+ { column => { '$lte' => end_date } }
241
+ end
242
+ when :datetime, :timestamp
243
+ start_date, end_date = get_filtering_duration(operator, value)
244
+
245
+ if start_date && end_date
246
+ { column => { '$gte' => start_date.to_time.beginning_of_day, '$lte' => end_date.to_time.end_of_day } }
247
+ elsif start_date
248
+ { column => { '$gte' => start_date.to_time.beginning_of_day } }
249
+ elsif end_date
250
+ { column => { '$lte' => end_date.to_time.end_of_day } }
251
+ end
252
+ when :enum
253
+ return if value.blank?
254
+ { column => { "$in" => Array.wrap(value) } }
255
+ when :belongs_to_association, :bson_object_id
256
+ object_id = (object_id_from_string(value) rescue nil)
257
+ { column => object_id } if object_id
258
+ end
259
+ end
260
+
261
+ def type_lookup(name, field)
262
+ {
263
+ "Array" => { :type => :serialized },
264
+ "BigDecimal" => { :type => :decimal },
265
+ "Boolean" => { :type => :boolean },
266
+ "BSON::ObjectId" => { :type => :bson_object_id, :serial? => (name == primary_key) },
267
+ "Moped::BSON::ObjectId" => { :type => :bson_object_id, :serial? => (name == primary_key) },
268
+ "Date" => { :type => :date },
269
+ "DateTime" => { :type => :datetime },
270
+ "ActiveSupport::TimeWithZone" => { :type => :datetime },
271
+ "Float" => { :type => :float },
272
+ "Hash" => { :type => :serialized },
273
+ "Money" => { :type => :serialized },
274
+ "Integer" => { :type => :integer },
275
+ "Object" => (
276
+ if associations.find{|a| a[:type] == :belongs_to && a[:foreign_key] == name.to_sym}
277
+ { :type => :bson_object_id }
278
+ else
279
+ { :type => :string, :length => 255 }
280
+ end
281
+ ),
282
+ "String" => (
283
+ if (length = length_validation_lookup(name)) && length < 256
284
+ { :type => :string, :length => length }
285
+ elsif STRING_TYPE_COLUMN_NAMES.include?(name.to_sym)
286
+ { :type => :string, :length => 255 }
287
+ else
288
+ { :type => :text }
289
+ end
290
+ ),
291
+ "Symbol" => { :type => :string, :length => 255 },
292
+ "Time" => { :type => :datetime },
293
+ }[field.type.to_s] or raise "Type #{field.type.to_s} for field :#{name} in #{model.inspect} not supported"
294
+ end
295
+
296
+ def association_model_proc_lookup(association)
297
+ if association.polymorphic? && [:referenced_in, :belongs_to].include?(association.macro)
298
+ RailsAdmin::AbstractModel.polymorphic_parents(:mongoid, self.model.model_name, association.name) || []
299
+ else
300
+ association.klass
301
+ end
302
+ end
303
+
304
+ def association_foreign_type_lookup(association)
305
+ if association.polymorphic? && [:referenced_in, :belongs_to].include?(association.macro)
306
+ association.inverse_type.try(:to_sym) || :"#{association.name}_type"
307
+ end
308
+ end
309
+
310
+ def association_foreign_inverse_of_lookup(association)
311
+ if association.polymorphic? && [:referenced_in, :belongs_to].include?(association.macro) && association.respond_to?(:inverse_of_field)
312
+ association.inverse_of_field.try(:to_sym)
313
+ end
314
+ end
315
+
316
+ def association_nested_attributes_options_lookup(association)
317
+ nested = model.nested_attributes_options.try { |o| o[association.name.to_sym] }
318
+ if !nested && [:embeds_one, :embeds_many].include?(association.macro.to_sym)
319
+ raise <<-MSG.gsub(/^\s+/, '')
320
+ Embbeded association without accepts_nested_attributes_for can't be handled by RailsAdmin,
321
+ because embedded model doesn't have top-level access.
322
+ Please add `accepts_nested_attributes_for :#{association.name}' line to `#{model.to_s}' model.
323
+ MSG
324
+ end
325
+ nested
326
+ end
327
+
328
+ def association_as_lookup(association)
329
+ association.as.try :to_sym
330
+ end
331
+
332
+ def association_polymorphic_lookup(association)
333
+ !!association.polymorphic? && [:referenced_in, :belongs_to].include?(association.macro)
334
+ end
335
+
336
+ def association_primary_key_lookup(association)
337
+ :_id # todo
338
+ end
339
+
340
+ def association_inverse_of_lookup(association)
341
+ association.inverse_of.try :to_sym
342
+ end
343
+
344
+ def association_foreign_key_lookup(association)
345
+ unless [:embeds_one, :embeds_many].include?(association.macro.to_sym)
346
+ association.foreign_key.to_sym rescue nil
347
+ end
348
+ end
349
+
350
+ def association_type_lookup(macro)
351
+ case macro.to_sym
352
+ when :belongs_to, :referenced_in, :embedded_in
353
+ :belongs_to
354
+ when :has_one, :references_one, :embeds_one
355
+ :has_one
356
+ when :has_many, :references_many, :embeds_many
357
+ :has_many
358
+ when :has_and_belongs_to_many, :references_and_referenced_in_many
359
+ :has_and_belongs_to_many
360
+ else
361
+ raise "Unknown association type: #{macro.inspect}"
362
+ end
363
+ end
364
+
365
+ def length_validation_lookup(name)
366
+ shortest = model.validators.select do |validator|
367
+ validator.respond_to?(:attributes) &&
368
+ validator.attributes.include?(name.to_sym) &&
369
+ validator.kind == :length &&
370
+ validator.options[:maximum]
371
+ end.min{|a, b| a.options[:maximum] <=> b.options[:maximum] }
372
+ if shortest
373
+ shortest.options[:maximum]
374
+ else
375
+ false
376
+ end
377
+ end
378
+
379
+ def parse_collection_name(column)
380
+ collection_name, column_name = column.split('.')
381
+ if [:embeds_one, :embeds_many].include?(model.associations[collection_name].try(:macro).try(:to_sym))
382
+ [table_name, column]
383
+ else
384
+ [collection_name, column_name]
385
+ end
386
+ end
387
+
388
+ def make_condition_for_current_collection(target_field, conditions_per_collection)
389
+ result =[]
390
+ conditions_per_collection.each do |collection_name, conditions|
391
+ if collection_name == table_name
392
+ # conditions referring current model column are passed directly
393
+ result.concat conditions
394
+ else
395
+ # otherwise, collect ids of documents that satisfy search condition
396
+ result.concat perform_search_on_associated_collection(target_field.name, conditions)
397
+ end
398
+ end
399
+ result
400
+ end
401
+
402
+ def perform_search_on_associated_collection(field_name, conditions)
403
+ target_association = associations.find{|a| a[:name] == field_name }
404
+ return [] unless target_association
405
+ model = target_association[:model_proc].call
406
+ case target_association[:type]
407
+ when :belongs_to, :has_and_belongs_to_many
408
+ [{ target_association[:foreign_key].to_s => { '$in' => model.where('$or' => conditions).all.map{|r| r.send(target_association[:primary_key_proc].call)} }}]
409
+ when :has_many
410
+ [{ target_association[:primary_key_proc].call.to_s => { '$in' => model.where('$or' => conditions).all.map{|r| r.send(target_association[:foreign_key])} }}]
411
+ end
412
+ end
413
+
414
+ def sort_by(options, scope)
415
+ return scope unless options[:sort]
416
+
417
+ field_name, collection_name = options[:sort].to_s.split('.').reverse
418
+ if collection_name && collection_name != table_name
419
+ # sorting by associated model column is not supported, so just ignore
420
+ return scope
421
+ end
422
+ if options[:sort_reverse]
423
+ scope.asc field_name
424
+ else
425
+ scope.desc field_name
426
+ end
427
+ end
428
+ end
429
+ end
430
+ end