activeadmin 1.4.3 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activeadmin might be problematic. Click here for more details.

Files changed (307) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +359 -25
  3. data/CONTRIBUTING.md +53 -74
  4. data/README.md +44 -11
  5. data/app/assets/javascripts/active_admin/base.js +517 -0
  6. data/app/assets/stylesheets/active_admin/_base.scss +29 -29
  7. data/app/assets/stylesheets/active_admin/_forms.scss +2 -14
  8. data/app/assets/stylesheets/active_admin/_header.scss +40 -8
  9. data/app/assets/stylesheets/active_admin/_mixins.scss +1 -1
  10. data/{vendor → app}/assets/stylesheets/active_admin/_normalize.scss +0 -0
  11. data/app/assets/stylesheets/active_admin/components/_comments.scss +2 -2
  12. data/app/assets/stylesheets/active_admin/components/_status_tags.scss +0 -5
  13. data/app/assets/stylesheets/active_admin/components/_tables.scss +1 -2
  14. data/app/assets/stylesheets/active_admin/components/_tabs.scss +1 -1
  15. data/app/assets/stylesheets/active_admin/mixins/_all.scss +8 -8
  16. data/app/assets/stylesheets/active_admin/mixins/_gradients.scss +1 -1
  17. data/app/assets/stylesheets/active_admin/mixins/_variables.scss +8 -0
  18. data/app/assets/stylesheets/active_admin/print.scss +2 -2
  19. data/app/assets/stylesheets/active_admin/structure/_main_structure.scss +1 -1
  20. data/app/javascript/active_admin/base.js +28 -0
  21. data/app/javascript/active_admin/ext/jquery-ui.js +7 -0
  22. data/app/javascript/active_admin/ext/jquery.js +9 -0
  23. data/app/javascript/active_admin/initializers/batch-actions.js +61 -0
  24. data/app/javascript/active_admin/initializers/checkbox-toggler.js +3 -0
  25. data/app/javascript/active_admin/initializers/datepicker.js +16 -0
  26. data/app/javascript/active_admin/initializers/dropdown-menu.js +9 -0
  27. data/app/javascript/active_admin/initializers/filters.js +10 -0
  28. data/app/javascript/active_admin/initializers/has-many.js +95 -0
  29. data/app/javascript/active_admin/initializers/per-page.js +13 -0
  30. data/app/javascript/active_admin/initializers/table-checkbox-toggler.js +3 -0
  31. data/app/javascript/active_admin/initializers/tabs.js +6 -0
  32. data/app/javascript/active_admin/lib/checkbox-toggler.js +49 -0
  33. data/app/javascript/active_admin/lib/dropdown-menu.js +116 -0
  34. data/app/javascript/active_admin/lib/filters.js +39 -0
  35. data/app/javascript/active_admin/lib/modal-dialog.js +63 -0
  36. data/app/javascript/active_admin/lib/per-page.js +38 -0
  37. data/app/javascript/active_admin/lib/table-checkbox-toggler.js +38 -0
  38. data/app/javascript/active_admin/lib/utils.js +40 -0
  39. data/app/views/active_admin/devise/confirmations/new.html.erb +1 -1
  40. data/app/views/active_admin/devise/mailer/reset_password_instructions.html.erb +1 -1
  41. data/app/views/active_admin/devise/mailer/unlock_instructions.html.erb +2 -2
  42. data/app/views/active_admin/devise/passwords/edit.html.erb +1 -1
  43. data/app/views/active_admin/devise/passwords/new.html.erb +1 -1
  44. data/app/views/active_admin/devise/registrations/new.html.erb +1 -2
  45. data/app/views/active_admin/devise/shared/_error_messages.html.erb +15 -0
  46. data/app/views/active_admin/devise/unlocks/new.html.erb +1 -1
  47. data/app/views/kaminari/active_admin_countless/_first_page.html.erb +11 -0
  48. data/app/views/kaminari/active_admin_countless/_gap.html.erb +8 -0
  49. data/app/views/kaminari/active_admin_countless/_next_page.html.erb +11 -0
  50. data/app/views/kaminari/active_admin_countless/_page.html.erb +12 -0
  51. data/app/views/kaminari/active_admin_countless/_paginator.html.erb +24 -0
  52. data/app/views/kaminari/active_admin_countless/_prev_page.html.erb +11 -0
  53. data/app/views/layouts/active_admin_logged_out.html.erb +16 -6
  54. data/config/locales/ar.yml +9 -8
  55. data/config/locales/az.yml +138 -0
  56. data/config/locales/bg.yml +1 -1
  57. data/config/locales/bs.yml +1 -0
  58. data/config/locales/ca.yml +1 -1
  59. data/config/locales/cs.yml +1 -0
  60. data/config/locales/da.yml +1 -0
  61. data/config/locales/de-CH.yml +1 -0
  62. data/config/locales/de.yml +19 -0
  63. data/config/locales/el.yml +1 -0
  64. data/config/locales/en-CA.yml +4 -3
  65. data/config/locales/en-GB.yml +4 -3
  66. data/config/locales/en.yml +4 -3
  67. data/config/locales/eo.yml +1 -0
  68. data/config/locales/es-MX.yml +3 -1
  69. data/config/locales/es.yml +6 -5
  70. data/config/locales/fa.yml +1 -0
  71. data/config/locales/fi.yml +1 -0
  72. data/config/locales/fr.yml +6 -5
  73. data/config/locales/he.yml +1 -1
  74. data/config/locales/hr.yml +1 -0
  75. data/config/locales/hu.yml +5 -0
  76. data/config/locales/id.yml +1 -0
  77. data/config/locales/it.yml +19 -0
  78. data/config/locales/ja.yml +4 -3
  79. data/config/locales/ko.yml +1 -0
  80. data/config/locales/lt.yml +3 -2
  81. data/config/locales/lv.yml +3 -2
  82. data/config/locales/mk.yml +134 -0
  83. data/config/locales/nb.yml +1 -0
  84. data/config/locales/nl.yml +1 -0
  85. data/config/locales/pl.yml +1 -0
  86. data/config/locales/pt-BR.yml +1 -0
  87. data/config/locales/pt-PT.yml +1 -0
  88. data/config/locales/ro.yml +1 -0
  89. data/config/locales/ru.yml +1 -0
  90. data/config/locales/sk.yml +60 -0
  91. data/config/locales/sv-SE.yml +1 -0
  92. data/config/locales/tr.yml +1 -0
  93. data/config/locales/uk.yml +3 -0
  94. data/config/locales/vi.yml +7 -5
  95. data/config/locales/zh-CN.yml +1 -0
  96. data/config/locales/zh-TW.yml +1 -0
  97. data/docs/0-installation.md +28 -4
  98. data/docs/1-general-configuration.md +20 -0
  99. data/docs/11-decorators.md +16 -5
  100. data/docs/12-arbre-components.md +13 -0
  101. data/docs/13-authorization-adapter.md +6 -6
  102. data/docs/2-resource-customization.md +11 -2
  103. data/docs/3-index-pages.md +1 -1
  104. data/docs/3-index-pages/index-as-table.md +7 -0
  105. data/docs/5-forms.md +6 -1
  106. data/docs/6-show-pages.md +12 -0
  107. data/docs/9-batch-actions.md +2 -2
  108. data/docs/CNAME +1 -1
  109. data/docs/Gemfile +2 -3
  110. data/docs/Gemfile.lock +126 -116
  111. data/docs/_config.yml +2 -0
  112. data/docs/_includes/top-menu.html +2 -2
  113. data/docs/documentation.md +1 -1
  114. data/docs/index.html +110 -9
  115. data/docs/stylesheets/main.css +29 -0
  116. data/lib/active_admin.rb +67 -63
  117. data/lib/active_admin/application.rb +20 -27
  118. data/lib/active_admin/application_settings.rb +6 -3
  119. data/lib/active_admin/asset_registration.rb +0 -8
  120. data/lib/active_admin/authorization_adapter.rb +3 -3
  121. data/lib/active_admin/base_controller.rb +10 -10
  122. data/lib/active_admin/base_controller/authorization.rb +15 -15
  123. data/lib/active_admin/batch_actions/controller.rb +4 -4
  124. data/lib/active_admin/batch_actions/resource_extension.rb +15 -10
  125. data/lib/active_admin/batch_actions/views/batch_action_form.rb +3 -3
  126. data/lib/active_admin/batch_actions/views/batch_action_selector.rb +6 -6
  127. data/lib/active_admin/batch_actions/views/selection_cells.rb +3 -3
  128. data/lib/active_admin/callbacks.rb +1 -1
  129. data/lib/active_admin/cancan_adapter.rb +1 -1
  130. data/lib/active_admin/collection_decorator.rb +31 -0
  131. data/lib/active_admin/controller_action.rb +2 -1
  132. data/lib/active_admin/csv_builder.rb +14 -9
  133. data/lib/active_admin/dependency.rb +13 -85
  134. data/lib/active_admin/devise.rb +5 -5
  135. data/lib/active_admin/dsl.rb +2 -9
  136. data/lib/active_admin/dynamic_settings_node.rb +2 -2
  137. data/lib/active_admin/engine.rb +10 -8
  138. data/lib/active_admin/error.rb +4 -4
  139. data/lib/active_admin/filters.rb +7 -7
  140. data/lib/active_admin/filters/active.rb +1 -1
  141. data/lib/active_admin/filters/active_filter.rb +10 -10
  142. data/lib/active_admin/filters/active_sidebar.rb +9 -5
  143. data/lib/active_admin/filters/forms.rb +7 -7
  144. data/lib/active_admin/filters/formtastic_addons.rb +2 -7
  145. data/lib/active_admin/filters/resource_extension.rb +28 -4
  146. data/lib/active_admin/form_builder.rb +26 -22
  147. data/lib/active_admin/generators/boilerplate.rb +12 -4
  148. data/lib/active_admin/helpers/optional_display.rb +2 -2
  149. data/lib/active_admin/helpers/scope_chain.rb +1 -0
  150. data/lib/active_admin/inputs/datepicker_input.rb +2 -2
  151. data/lib/active_admin/inputs/filters/base.rb +1 -1
  152. data/lib/active_admin/inputs/filters/base/search_method_select.rb +6 -6
  153. data/lib/active_admin/inputs/filters/boolean_input.rb +1 -1
  154. data/lib/active_admin/inputs/filters/check_boxes_input.rb +1 -1
  155. data/lib/active_admin/inputs/filters/date_range_input.rb +15 -12
  156. data/lib/active_admin/inputs/filters/select_input.rb +2 -2
  157. data/lib/active_admin/localizers.rb +1 -1
  158. data/lib/active_admin/localizers/resource_localizer.rb +3 -3
  159. data/lib/active_admin/menu.rb +6 -3
  160. data/lib/active_admin/menu_item.rb +7 -7
  161. data/lib/active_admin/namespace.rb +12 -12
  162. data/lib/active_admin/namespace_settings.rb +27 -8
  163. data/lib/active_admin/order_clause.rb +2 -2
  164. data/lib/active_admin/orm/active_record.rb +1 -1
  165. data/lib/active_admin/orm/active_record/comments.rb +23 -23
  166. data/lib/active_admin/orm/active_record/comments/comment.rb +4 -4
  167. data/lib/active_admin/orm/active_record/comments/views.rb +2 -2
  168. data/lib/active_admin/orm/active_record/comments/views/active_admin_comments.rb +29 -24
  169. data/lib/active_admin/page.rb +1 -1
  170. data/lib/active_admin/page_dsl.rb +1 -1
  171. data/lib/active_admin/page_presenter.rb +2 -1
  172. data/lib/active_admin/pundit_adapter.rb +22 -9
  173. data/lib/active_admin/resource.rb +34 -20
  174. data/lib/active_admin/resource/action_items.rb +5 -5
  175. data/lib/active_admin/resource/attributes.rb +8 -5
  176. data/lib/active_admin/resource/belongs_to.rb +8 -3
  177. data/lib/active_admin/resource/controllers.rb +1 -1
  178. data/lib/active_admin/resource/menu.rb +5 -5
  179. data/lib/active_admin/resource/model.rb +15 -0
  180. data/lib/active_admin/resource/naming.rb +5 -5
  181. data/lib/active_admin/resource/routes.rb +25 -14
  182. data/lib/active_admin/resource/scope_to.rb +7 -7
  183. data/lib/active_admin/resource/scopes.rb +3 -3
  184. data/lib/active_admin/resource/sidebars.rb +2 -2
  185. data/lib/active_admin/resource_collection.rb +2 -2
  186. data/lib/active_admin/resource_controller.rb +13 -10
  187. data/lib/active_admin/resource_controller/action_builder.rb +10 -0
  188. data/lib/active_admin/resource_controller/data_access.rb +1 -1
  189. data/lib/active_admin/resource_controller/decorators.rb +7 -29
  190. data/lib/active_admin/resource_controller/polymorphic_routes.rb +37 -0
  191. data/lib/active_admin/resource_controller/resource_class_methods.rb +2 -0
  192. data/lib/active_admin/resource_controller/streaming.rb +7 -6
  193. data/lib/active_admin/resource_dsl.rb +11 -9
  194. data/lib/active_admin/router.rb +3 -2
  195. data/lib/active_admin/scope.rb +15 -11
  196. data/lib/active_admin/settings_node.rb +1 -1
  197. data/lib/active_admin/sidebar_section.rb +3 -1
  198. data/lib/active_admin/version.rb +1 -1
  199. data/lib/active_admin/view_factory.rb +17 -17
  200. data/lib/active_admin/view_helpers.rb +1 -1
  201. data/lib/active_admin/view_helpers/breadcrumb_helper.rb +5 -5
  202. data/lib/active_admin/view_helpers/display_helper.rb +16 -7
  203. data/lib/active_admin/view_helpers/download_format_links_helper.rb +2 -1
  204. data/lib/active_admin/view_helpers/fields_for.rb +2 -2
  205. data/lib/active_admin/view_helpers/method_or_proc_helper.rb +2 -0
  206. data/lib/active_admin/views.rb +1 -1
  207. data/lib/active_admin/views/components/active_admin_form.rb +12 -6
  208. data/lib/active_admin/views/components/attributes_table.rb +8 -8
  209. data/lib/active_admin/views/components/blank_slate.rb +1 -1
  210. data/lib/active_admin/views/components/dropdown_menu.rb +8 -8
  211. data/lib/active_admin/views/components/index_list.rb +3 -3
  212. data/lib/active_admin/views/components/menu.rb +1 -1
  213. data/lib/active_admin/views/components/menu_item.rb +4 -4
  214. data/lib/active_admin/views/components/paginated_collection.rb +21 -20
  215. data/lib/active_admin/views/components/panel.rb +1 -1
  216. data/lib/active_admin/views/components/scopes.rb +7 -5
  217. data/lib/active_admin/views/components/sidebar_section.rb +0 -3
  218. data/lib/active_admin/views/components/site_title.rb +1 -1
  219. data/lib/active_admin/views/components/status_tag.rb +13 -26
  220. data/lib/active_admin/views/components/table_for.rb +20 -19
  221. data/lib/active_admin/views/components/tabs.rb +13 -4
  222. data/lib/active_admin/views/footer.rb +3 -2
  223. data/lib/active_admin/views/header.rb +2 -2
  224. data/lib/active_admin/views/index_as_blog.rb +1 -1
  225. data/lib/active_admin/views/index_as_grid.rb +1 -1
  226. data/lib/active_admin/views/index_as_table.rb +27 -19
  227. data/lib/active_admin/views/pages/base.rb +18 -11
  228. data/lib/active_admin/views/pages/index.rb +15 -13
  229. data/lib/active_admin/views/tabbed_navigation.rb +2 -2
  230. data/lib/active_admin/views/title_bar.rb +1 -1
  231. data/lib/activeadmin.rb +1 -1
  232. data/lib/generators/active_admin/assets/assets_generator.rb +2 -2
  233. data/lib/generators/active_admin/assets/templates/active_admin.js +1 -0
  234. data/lib/generators/active_admin/assets/templates/active_admin.scss +2 -2
  235. data/lib/generators/active_admin/devise/devise_generator.rb +5 -5
  236. data/lib/generators/active_admin/install/install_generator.rb +18 -8
  237. data/lib/generators/active_admin/install/templates/active_admin.rb.erb +45 -3
  238. data/lib/generators/active_admin/install/templates/dashboard.rb +2 -3
  239. data/lib/generators/active_admin/install/templates/migrations/create_active_admin_comments.rb.erb +1 -15
  240. data/lib/generators/active_admin/page/page_generator.rb +1 -1
  241. data/lib/generators/active_admin/resource/resource_generator.rb +3 -3
  242. data/lib/generators/active_admin/resource/templates/admin.rb.erb +40 -37
  243. data/lib/generators/active_admin/webpacker/plugins/jquery.js +7 -0
  244. data/lib/generators/active_admin/webpacker/templates/active_admin.js +5 -0
  245. data/lib/generators/active_admin/webpacker/templates/active_admin.scss +17 -0
  246. data/lib/generators/active_admin/webpacker/templates/print.scss +2 -0
  247. data/lib/generators/active_admin/webpacker/webpacker_generator.rb +26 -0
  248. data/lib/ransack_ext.rb +9 -9
  249. data/vendor/assets/javascripts/jquery-ui/form-reset-mixin.js +80 -0
  250. data/vendor/assets/javascripts/jquery-ui/form.js +22 -0
  251. data/vendor/assets/javascripts/jquery-ui/labels.js +65 -0
  252. data/vendor/assets/javascripts/jquery-ui/widgets/checkboxradio.js +274 -283
  253. metadata +108 -127
  254. data/.circleci/config.yml +0 -572
  255. data/.github/ISSUE_TEMPLATE.md +0 -20
  256. data/.gitignore +0 -16
  257. data/.mdlrc +0 -1
  258. data/.rspec +0 -1
  259. data/.rspec_parallel +0 -2
  260. data/.rubocop.yml +0 -99
  261. data/.simplecov +0 -9
  262. data/.yardopts +0 -7
  263. data/Gemfile +0 -30
  264. data/Gemfile.common +0 -26
  265. data/Gemfile.lock +0 -433
  266. data/Rakefile +0 -24
  267. data/activeadmin.gemspec +0 -32
  268. data/app/assets/images/active_admin/nested_menu_arrow.gif +0 -0
  269. data/app/assets/images/active_admin/nested_menu_arrow_dark.gif +0 -0
  270. data/app/assets/images/active_admin/orderable.png +0 -0
  271. data/app/assets/javascripts/active_admin/base.js.coffee +0 -13
  272. data/app/assets/javascripts/active_admin/ext/jquery-ui.js.coffee +0 -6
  273. data/app/assets/javascripts/active_admin/ext/jquery.js.coffee +0 -7
  274. data/app/assets/javascripts/active_admin/initializers/batch_actions.js.coffee +0 -11
  275. data/app/assets/javascripts/active_admin/initializers/datepicker.js.coffee +0 -14
  276. data/app/assets/javascripts/active_admin/initializers/filters.js.coffee +0 -26
  277. data/app/assets/javascripts/active_admin/initializers/tabs.js.coffee +0 -7
  278. data/app/assets/javascripts/active_admin/lib/batch_actions.js.coffee +0 -42
  279. data/app/assets/javascripts/active_admin/lib/checkbox-toggler.js.coffee +0 -46
  280. data/app/assets/javascripts/active_admin/lib/dropdown-menu.js.coffee +0 -104
  281. data/app/assets/javascripts/active_admin/lib/flash.js.coffee +0 -19
  282. data/app/assets/javascripts/active_admin/lib/has_many.js.coffee +0 -79
  283. data/app/assets/javascripts/active_admin/lib/modal_dialog.js.coffee +0 -45
  284. data/app/assets/javascripts/active_admin/lib/per_page.js.coffee +0 -46
  285. data/app/assets/javascripts/active_admin/lib/table-checkbox-toggler.js.coffee +0 -22
  286. data/bin/install_chromedriver.sh +0 -17
  287. data/config/i18n-tasks.yml +0 -26
  288. data/config/mdl_style.rb +0 -11
  289. data/cucumber.yml +0 -7
  290. data/gemfiles/rails_42.gemfile +0 -10
  291. data/gemfiles/rails_42.gemfile.lock +0 -339
  292. data/gemfiles/rails_50.gemfile +0 -10
  293. data/gemfiles/rails_50.gemfile.lock +0 -353
  294. data/gemfiles/rails_51.gemfile +0 -10
  295. data/gemfiles/rails_51.gemfile.lock +0 -353
  296. data/lib/active_admin/event.rb +0 -24
  297. data/lib/active_admin/helpers/output_safety_helper.rb +0 -35
  298. data/lib/active_admin/reloader.rb +0 -25
  299. data/lib/bug_report_templates/active_admin_master.rb +0 -111
  300. data/lib/generators/active_admin/assets/templates/active_admin.js.coffee +0 -1
  301. data/tasks/application_generator.rb +0 -50
  302. data/tasks/docs.rake +0 -64
  303. data/tasks/gemfiles.rake +0 -8
  304. data/tasks/lint.rake +0 -110
  305. data/tasks/local.rake +0 -27
  306. data/tasks/release.rake +0 -6
  307. data/tasks/test.rake +0 -42
@@ -123,25 +123,49 @@ module ActiveAdmin
123
123
  # Returns a default set of filters for the associations
124
124
  def default_association_filters
125
125
  if resource_class.respond_to?(:reflect_on_all_associations)
126
- poly, not_poly = resource_class.reflect_on_all_associations.partition{ |r| r.macro == :belongs_to && r.options[:polymorphic] }
126
+ poly, not_poly = resource_class.reflect_on_all_associations.partition { |r| r.macro == :belongs_to && r.options[:polymorphic] }
127
127
 
128
128
  # remove deeply nested associations
129
- not_poly.reject!{ |r| r.chain.length > 2 }
129
+ not_poly.reject! { |r| r.chain.length > 2 }
130
130
 
131
131
  filters = poly.map(&:foreign_type) + not_poly.map(&:name)
132
+
133
+ # Check high-arity associations for filterable columns
134
+ max = namespace.maximum_association_filter_arity
135
+ if max != :unlimited
136
+ high_arity, low_arity = not_poly.partition do |r|
137
+ r.klass.reorder(nil).limit(max + 1).count > max
138
+ end
139
+
140
+ # Remove high-arity associations with no searchable column
141
+ high_arity = high_arity.select(&method(:searchable_column_for))
142
+
143
+ high_arity = high_arity.map { |r| r.name.to_s + "_" + searchable_column_for(r) + namespace.filter_method_for_large_association }
144
+
145
+ filters = poly.map(&:foreign_type) + low_arity.map(&:name) + high_arity
146
+ end
147
+
132
148
  filters.map &:to_sym
133
149
  else
134
150
  []
135
151
  end
136
152
  end
137
153
 
154
+ def search_columns
155
+ @search_columns ||= namespace.filter_columns_for_large_association.map(&:to_s)
156
+ end
157
+
158
+ def searchable_column_for(relation)
159
+ relation.klass.column_names.find { |name| search_columns.include?(name) }
160
+ end
161
+
138
162
  def add_filters_sidebar_section
139
163
  self.sidebar_sections << filters_sidebar_section
140
164
  end
141
165
 
142
166
  def filters_sidebar_section
143
- ActiveAdmin::SidebarSection.new :filters, only: :index, if: ->{ active_admin_config.filters.any? } do
144
- active_admin_filters_form_for assigns[:search], active_admin_config.filters
167
+ ActiveAdmin::SidebarSection.new :filters, only: :index, if: -> { active_admin_config.filters.any? } do
168
+ active_admin_filters_form_for assigns[:search], **active_admin_config.filters
145
169
  end
146
170
  end
147
171
 
@@ -20,9 +20,9 @@ module ActiveAdmin
20
20
  self.input_class_finder = ::Formtastic::InputClassFinder
21
21
  self.action_class_finder = ::Formtastic::ActionClassFinder
22
22
 
23
- def cancel_link(url = {action: "index"}, html_options = {}, li_attrs = {})
23
+ def cancel_link(url = { action: "index" }, html_options = {}, li_attrs = {})
24
24
  li_attrs[:class] ||= "cancel"
25
- li_content = template.link_to I18n.t('active_admin.cancel'), url, html_options
25
+ li_content = template.link_to I18n.t("active_admin.cancel"), url, html_options
26
26
  template.content_tag(:li, li_content, li_attrs)
27
27
  end
28
28
 
@@ -40,14 +40,14 @@ module ActiveAdmin
40
40
  attr_reader :assoc
41
41
  attr_reader :options
42
42
  attr_reader :heading, :sortable_column, :sortable_start
43
- attr_reader :new_record, :destroy_option
43
+ attr_reader :new_record, :destroy_option, :remove_record
44
44
 
45
45
  def initialize(has_many_form, assoc, options)
46
46
  super has_many_form
47
47
  @assoc = assoc
48
48
  @options = extract_custom_settings!(options.dup)
49
49
  @options.reverse_merge!(for: assoc)
50
- @options[:class] = [options[:class], "inputs has_many_fields"].compact.join(' ')
50
+ @options[:class] = [options[:class], "inputs has_many_fields"].compact.join(" ")
51
51
 
52
52
  if sortable_column
53
53
  @options[:for] = [assoc, sorted_children(sortable_column)]
@@ -69,9 +69,10 @@ module ActiveAdmin
69
69
  def extract_custom_settings!(options)
70
70
  @heading = options.key?(:heading) ? options.delete(:heading) : default_heading
71
71
  @sortable_column = options.delete(:sortable)
72
- @sortable_start = options.delete(:sortable_start) || 0
72
+ @sortable_start = options.delete(:sortable_start) || 0
73
73
  @new_record = options.key?(:new_record) ? options.delete(:new_record) : true
74
74
  @destroy_option = options.delete(:allow_destroy)
75
+ @remove_record = options.delete(:remove_record)
75
76
  options
76
77
  end
77
78
 
@@ -93,7 +94,7 @@ module ActiveAdmin
93
94
  contents = without_wrapper { inputs(options, &form_block) }
94
95
  contents ||= "".html_safe
95
96
 
96
- js = new_record ? js_for_has_many(options[:class], &form_block) : ''
97
+ js = new_record ? js_for_has_many(options[:class], &form_block) : ""
97
98
  contents << js
98
99
  end
99
100
 
@@ -107,19 +108,21 @@ module ActiveAdmin
107
108
  def has_many_actions(form_builder, contents)
108
109
  if form_builder.object.new_record?
109
110
  contents << template.content_tag(:li) do
110
- template.link_to I18n.t('active_admin.has_many_remove'), "#", class: 'button has_many_remove'
111
+ remove_text = remove_record.is_a?(String) ? remove_record : I18n.t("active_admin.has_many_remove")
112
+ template.link_to remove_text, "#", class: "button has_many_remove"
111
113
  end
112
114
  elsif allow_destroy?(form_builder.object)
113
- form_builder.input(:_destroy, as: :boolean,
114
- wrapper_html: {class: 'has_many_delete'},
115
- label: I18n.t('active_admin.has_many_delete'))
115
+ form_builder.input(
116
+ :_destroy, as: :boolean,
117
+ wrapper_html: { class: "has_many_delete" },
118
+ label: I18n.t("active_admin.has_many_delete"))
116
119
  end
117
120
 
118
121
  if sortable_column
119
122
  form_builder.input sortable_column, as: :hidden
120
123
 
121
- contents << template.content_tag(:li, class: 'handle') do
122
- I18n.t('active_admin.move')
124
+ contents << template.content_tag(:li, class: "handle") do
125
+ I18n.t("active_admin.move")
123
126
  end
124
127
  end
125
128
 
@@ -156,27 +159,28 @@ module ActiveAdmin
156
159
 
157
160
  # Capture the ADD JS
158
161
  def js_for_has_many(class_string, &form_block)
159
- assoc_name = assoc_klass.model_name
160
- placeholder = "NEW_#{assoc_name.to_s.underscore.upcase.gsub(/\//, '_')}_RECORD"
162
+ assoc_name = assoc_klass.model_name
163
+ placeholder = "NEW_#{assoc_name.to_s.underscore.upcase.gsub(/\//, '_')}_RECORD"
161
164
  opts = {
162
165
  for: [assoc, assoc_klass.new],
163
166
  class: class_string,
164
167
  for_options: { child_index: placeholder }
165
168
  }
166
- html = template.capture{ __getobj__.send(:inputs_for_nested_attributes, opts, &form_block) }
167
- text = new_record.is_a?(String) ? new_record : I18n.t('active_admin.has_many_new', model: assoc_name.human)
169
+ html = template.capture { __getobj__.send(:inputs_for_nested_attributes, opts, &form_block) }
170
+ text = new_record.is_a?(String) ? new_record : I18n.t("active_admin.has_many_new", model: assoc_name.human)
168
171
 
169
- template.link_to text, '#', class: "button has_many_add", data: {
172
+ template.link_to text, "#", class: "button has_many_add", data: {
170
173
  html: CGI.escapeHTML(html).html_safe, placeholder: placeholder
171
174
  }
172
175
  end
173
176
 
174
177
  def wrap_div_or_li(html)
175
- template.content_tag(already_in_an_inputs_block ? :li : :div,
176
- html,
177
- class: "has_many_container #{assoc}",
178
- 'data-sortable' => sortable_column,
179
- 'data-sortable-start' => sortable_start)
178
+ template.content_tag(
179
+ already_in_an_inputs_block ? :li : :div,
180
+ html,
181
+ class: "has_many_container #{assoc}",
182
+ "data-sortable" => sortable_column,
183
+ "data-sortable-start" => sortable_start)
180
184
  end
181
185
  end
182
186
  end
@@ -9,8 +9,16 @@ module ActiveAdmin
9
9
  @class_name.constantize.new.attributes.keys
10
10
  end
11
11
 
12
+ def assignable_attributes
13
+ attributes - %w(id created_at updated_at)
14
+ end
15
+
16
+ def permit_params
17
+ assignable_attributes.map { |a| a.to_sym.inspect }.join(", ")
18
+ end
19
+
12
20
  def rows
13
- attributes.map { |a| row(a) }.join("\n")
21
+ attributes.map { |a| row(a) }.join("\n ")
14
22
  end
15
23
 
16
24
  def row(name)
@@ -18,7 +26,7 @@ module ActiveAdmin
18
26
  end
19
27
 
20
28
  def columns
21
- attributes.map { |a| column(a) }.join("\n")
29
+ attributes.map { |a| column(a) }.join("\n ")
22
30
  end
23
31
 
24
32
  def column(name)
@@ -26,7 +34,7 @@ module ActiveAdmin
26
34
  end
27
35
 
28
36
  def filters
29
- attributes.map { |a| filter(a) }.join("\n")
37
+ attributes.map { |a| filter(a) }.join("\n ")
30
38
  end
31
39
 
32
40
  def filter(name)
@@ -34,7 +42,7 @@ module ActiveAdmin
34
42
  end
35
43
 
36
44
  def form_inputs
37
- attributes.reject{|a| %w(id created_at updated_at).include? a}.map{ |a| form_input(a) }.join("\n")
45
+ assignable_attributes.map { |a| form_input(a) }.join("\n ")
38
46
  end
39
47
 
40
48
  def form_input(name)
@@ -15,7 +15,7 @@ module ActiveAdmin
15
15
 
16
16
  module OptionalDisplay
17
17
  def display_on?(action, render_context = self)
18
- return false if @options[:only] && !@options[:only].include?(action.to_sym)
18
+ return false if @options[:only] && !@options[:only].include?(action.to_sym)
19
19
  return false if @options[:except] && @options[:except].include?(action.to_sym)
20
20
 
21
21
  case condition = @options[:if]
@@ -31,7 +31,7 @@ module ActiveAdmin
31
31
  private
32
32
 
33
33
  def normalize_display_options!
34
- @options[:only] = Array(@options[:only]) if @options[:only]
34
+ @options[:only] = Array(@options[:only]) if @options[:only]
35
35
  @options[:except] = Array(@options[:except]) if @options[:except]
36
36
  end
37
37
  end
@@ -1,5 +1,6 @@
1
1
  module ActiveAdmin
2
2
  module ScopeChain
3
+ private
3
4
  # Scope an ActiveRecord::Relation chain
4
5
  #
5
6
  # Example:
@@ -3,7 +3,7 @@ module ActiveAdmin
3
3
  class DatepickerInput < ::Formtastic::Inputs::StringInput
4
4
  def input_html_options
5
5
  super.tap do |options|
6
- options[:class] = [options[:class], "datepicker"].compact.join(' ')
6
+ options[:class] = [options[:class], "datepicker"].compact.join(" ")
7
7
  options[:data] ||= {}
8
8
  options[:data].merge! datepicker_options
9
9
  end
@@ -19,7 +19,7 @@ module ActiveAdmin
19
19
  private
20
20
  def datepicker_options
21
21
  options = self.options.fetch(:datepicker_options, {})
22
- options = Hash[options.map{ |k, v| [k.to_s.camelcase(:lower), v] }]
22
+ options = Hash[options.map { |k, v| [k.to_s.camelcase(:lower), v] }]
23
23
  { datepicker_options: options }
24
24
  end
25
25
  end
@@ -25,7 +25,7 @@ module ActiveAdmin
25
25
 
26
26
  def wrapper_html_options
27
27
  opts = super
28
- (opts[:class] ||= '') << " filter_form_field filter_#{as}"
28
+ (opts[:class] ||= "") << " filter_form_field filter_#{as}"
29
29
  opts
30
30
  end
31
31
 
@@ -31,15 +31,15 @@ module ActiveAdmin
31
31
 
32
32
  def wrapper_html_options
33
33
  opts = super
34
- (opts[:class] ||= '') << ' select_and_search' unless seems_searchable?
34
+ (opts[:class] ||= "") << " select_and_search" unless seems_searchable?
35
35
  opts
36
36
  end
37
37
 
38
38
  def to_html
39
39
  input_wrapping do
40
- label_html << # your label
40
+ label_html << # your label
41
41
  select_html << # the dropdown that holds the available search methods
42
- input_html # your input field
42
+ input_html # your input field
43
43
  end
44
44
  end
45
45
 
@@ -48,7 +48,7 @@ module ActiveAdmin
48
48
  end
49
49
 
50
50
  def select_html
51
- template.select_tag '', template.options_for_select(filter_options, current_filter)
51
+ template.select_tag "", template.options_for_select(filter_options, current_filter)
52
52
  end
53
53
 
54
54
  def filters
@@ -57,8 +57,8 @@ module ActiveAdmin
57
57
 
58
58
  def current_filter
59
59
  @current_filter ||= begin
60
- methods = filters.map{ |f| "#{method}_#{f}" }
61
- methods.detect{ |m| @object.public_send m } || methods.first
60
+ methods = filters.map { |f| "#{method}_#{f}" }
61
+ methods.detect { |m| @object.public_send m } || methods.first
62
62
  end
63
63
  end
64
64
 
@@ -16,7 +16,7 @@ module ActiveAdmin
16
16
 
17
17
  # Provide the AA translation to the blank input field.
18
18
  def include_blank
19
- I18n.t 'active_admin.any' if super
19
+ I18n.t "active_admin.any" if super
20
20
  end
21
21
  end
22
22
  end
@@ -22,7 +22,7 @@ module ActiveAdmin
22
22
 
23
23
  # Add whitespace before label
24
24
  def choice_label(choice)
25
- ' ' + super
25
+ " " + super
26
26
  end
27
27
 
28
28
  # Don't wrap in UL tag
@@ -7,8 +7,8 @@ module ActiveAdmin
7
7
  def to_html
8
8
  input_wrapping do
9
9
  [ label_html,
10
- builder.text_field(gt_input_name, input_html_options(gt_input_name, gt_input_placeholder)),
11
- builder.text_field(lt_input_name, input_html_options(lt_input_name, lt_input_placeholder)),
10
+ builder.text_field(gt_input_name, input_html_options_for(gt_input_name, gt_input_placeholder)),
11
+ builder.text_field(lt_input_name, input_html_options_for(lt_input_name, lt_input_placeholder)),
12
12
  ].join("\n").html_safe
13
13
  end
14
14
  end
@@ -22,18 +22,21 @@ module ActiveAdmin
22
22
  column && column.type == :date ? "#{method}_lteq" : "#{method}_lteq_datetime"
23
23
  end
24
24
 
25
- def input_html_options(input_name = gt_input_name, placeholder = gt_input_placeholder)
26
- current_value = begin
27
- #cast value to date object before rendering input
28
- @object.public_send(input_name).to_s.to_date
29
- rescue
30
- nil
31
- end
25
+ def input_html_options
32
26
  { size: 12,
33
27
  class: "datepicker",
34
- maxlength: 10,
35
- placeholder: placeholder,
36
- value: current_value ? current_value.strftime("%Y-%m-%d") : "" }
28
+ maxlength: 10 }.merge(options[:input_html] || {})
29
+ end
30
+
31
+ def input_html_options_for(input_name, placeholder)
32
+ current_value = begin
33
+ #cast value to date object before rendering input
34
+ @object.public_send(input_name).to_s.to_date
35
+ rescue
36
+ nil
37
+ end
38
+ { placeholder: placeholder,
39
+ value: current_value ? current_value.strftime("%Y-%m-%d") : "" }.merge(input_html_options)
37
40
  end
38
41
 
39
42
  def gt_input_placeholder
@@ -7,7 +7,7 @@ module ActiveAdmin
7
7
  def input_name
8
8
  return method if seems_searchable?
9
9
 
10
- searchable_method_name + (multiple? ? '_in' : '_eq')
10
+ searchable_method_name + (multiple? ? "_in" : "_eq")
11
11
  end
12
12
 
13
13
  def searchable_method_name
@@ -22,7 +22,7 @@ module ActiveAdmin
22
22
 
23
23
  # Provide the AA translation to the blank input field.
24
24
  def include_blank
25
- I18n.t 'active_admin.any' if super
25
+ I18n.t "active_admin.any" if super
26
26
  end
27
27
 
28
28
  def input_html_options_name
@@ -1,4 +1,4 @@
1
- require 'active_admin/localizers/resource_localizer'
1
+ require "active_admin/localizers/resource_localizer"
2
2
 
3
3
  module ActiveAdmin
4
4
  module Localizers
@@ -19,16 +19,16 @@ module ActiveAdmin
19
19
 
20
20
  def translate(key, options = {})
21
21
  scope = options.delete(:scope)
22
- specific_key = array_to_key('resources', @model_name, scope, key)
22
+ specific_key = array_to_key("resources", @model_name, scope, key)
23
23
  defaults = [array_to_key(scope, key), key.to_s.titleize]
24
- ::I18n.t specific_key, options.reverse_merge(model: @model, default: defaults, scope: 'active_admin')
24
+ ::I18n.t specific_key, **options.reverse_merge(model: @model, default: defaults, scope: "active_admin")
25
25
  end
26
26
  alias_method :t, :translate
27
27
 
28
28
  protected
29
29
 
30
30
  def array_to_key(*arr)
31
- arr.flatten.compact.join('.').to_sym
31
+ arr.flatten.compact.join(".").to_sym
32
32
  end
33
33
  end
34
34
  end
@@ -47,7 +47,10 @@ module ActiveAdmin
47
47
  # menu.add parent: 'Dashboard', label: 'My Child Dashboard'
48
48
  #
49
49
  def add(options)
50
- item = if parent = options.delete(:parent)
50
+ parent_chain = Array.wrap(options.delete(:parent))
51
+
52
+ item = if parent = parent_chain.shift
53
+ options[:parent] = parent_chain if parent_chain.any?
51
54
  (self[parent] || add(label: parent)).add options
52
55
  else
53
56
  _add options.merge parent: self
@@ -60,7 +63,7 @@ module ActiveAdmin
60
63
 
61
64
  # Whether any children match the given item.
62
65
  def include?(item)
63
- @children.values.include? item
66
+ @children.values.include?(item) || @children.values.any? { |child| child.include?(item) }
64
67
  end
65
68
 
66
69
  # Used in the UI to visually distinguish which menu item is selected.
@@ -87,7 +90,7 @@ module ActiveAdmin
87
90
  def normalize_id(id)
88
91
  case id
89
92
  when String, Symbol, ActiveModel::Name
90
- id.to_s.downcase.tr ' ', '_'
93
+ id.to_s.downcase.tr " ", "_"
91
94
  when ActiveAdmin::Resource::Name
92
95
  id.param_key
93
96
  else