activeadmin 2.12.0 → 3.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 (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +230 -0
  3. data/CONTRIBUTING.md +4 -12
  4. data/README.md +4 -4
  5. data/app/assets/javascripts/active_admin/base.js +1 -4
  6. data/app/assets/stylesheets/active_admin/_forms.scss +2 -3
  7. data/app/assets/stylesheets/active_admin/components/_comments.scss +1 -1
  8. data/app/assets/stylesheets/active_admin/components/_dropdown_menu.scss +7 -4
  9. data/app/assets/stylesheets/active_admin/components/_pagination.scss +5 -2
  10. data/app/assets/stylesheets/active_admin/components/_table_tools.scss +9 -6
  11. data/app/assets/stylesheets/active_admin/components/_tabs.scss +10 -7
  12. data/app/assets/stylesheets/active_admin/mixins/_buttons.scss +2 -2
  13. data/app/assets/stylesheets/active_admin/pages/_logged_out.scss +1 -1
  14. data/app/assets/stylesheets/active_admin/structure/_footer.scss +6 -1
  15. data/app/assets/stylesheets/active_admin/structure/_title_bar.scss +6 -3
  16. data/app/views/layouts/active_admin_logged_out.html.erb +5 -4
  17. data/config/locales/ar.yml +0 -7
  18. data/config/locales/az.yml +0 -7
  19. data/config/locales/bg.yml +0 -7
  20. data/config/locales/bs.yml +0 -7
  21. data/config/locales/ca.yml +0 -7
  22. data/config/locales/cs.yml +0 -7
  23. data/config/locales/da.yml +0 -7
  24. data/config/locales/de-CH.yml +0 -7
  25. data/config/locales/de.yml +0 -8
  26. data/config/locales/el.yml +0 -7
  27. data/config/locales/en-CA.yml +0 -7
  28. data/config/locales/en-GB.yml +0 -7
  29. data/config/locales/en.yml +0 -8
  30. data/config/locales/eo.yml +0 -8
  31. data/config/locales/es-MX.yml +0 -7
  32. data/config/locales/es.yml +0 -8
  33. data/config/locales/fa.yml +0 -7
  34. data/config/locales/fi.yml +0 -7
  35. data/config/locales/fr.yml +3 -11
  36. data/config/locales/he.yml +0 -9
  37. data/config/locales/hr.yml +0 -7
  38. data/config/locales/hu.yml +0 -8
  39. data/config/locales/id.yml +0 -7
  40. data/config/locales/it.yml +0 -8
  41. data/config/locales/ja.yml +0 -8
  42. data/config/locales/ko.yml +0 -7
  43. data/config/locales/lt.yml +0 -8
  44. data/config/locales/lv.yml +0 -7
  45. data/config/locales/mk.yml +0 -8
  46. data/config/locales/nb.yml +0 -8
  47. data/config/locales/nl.yml +0 -8
  48. data/config/locales/pl.yml +0 -8
  49. data/config/locales/pt-BR.yml +0 -8
  50. data/config/locales/pt-PT.yml +0 -7
  51. data/config/locales/ro.yml +0 -7
  52. data/config/locales/ru.yml +0 -6
  53. data/config/locales/sk.yml +0 -8
  54. data/config/locales/sv-SE.yml +58 -39
  55. data/config/locales/tr.yml +0 -11
  56. data/config/locales/uk.yml +0 -6
  57. data/config/locales/vi.yml +34 -15
  58. data/config/locales/zh-CN.yml +34 -23
  59. data/config/locales/zh-TW.yml +0 -7
  60. data/lib/active_admin/application.rb +4 -4
  61. data/lib/active_admin/asset_registration.rb +3 -3
  62. data/lib/active_admin/authorization_adapter.rb +2 -0
  63. data/lib/active_admin/base_controller/authorization.rb +2 -2
  64. data/lib/active_admin/csv_builder.rb +23 -2
  65. data/lib/active_admin/dependency.rb +0 -4
  66. data/lib/active_admin/engine.rb +5 -1
  67. data/lib/active_admin/filters/active_filter.rb +1 -1
  68. data/lib/active_admin/filters/forms.rb +2 -2
  69. data/lib/active_admin/filters/formtastic_addons.rb +1 -1
  70. data/lib/active_admin/filters/resource_extension.rb +4 -4
  71. data/lib/active_admin/form_builder.rb +5 -6
  72. data/lib/active_admin/inputs/filters/base/search_method_select.rb +2 -2
  73. data/lib/active_admin/inputs/filters/date_range_input.rb +2 -2
  74. data/lib/active_admin/inputs/filters/numeric_input.rb +1 -1
  75. data/lib/active_admin/inputs/filters/select_input.rb +3 -3
  76. data/lib/active_admin/inputs/filters/string_input.rb +1 -1
  77. data/lib/active_admin/menu.rb +1 -0
  78. data/lib/active_admin/namespace.rb +3 -3
  79. data/lib/active_admin/namespace_settings.rb +1 -1
  80. data/lib/active_admin/orm/active_record/comments/comment.rb +8 -0
  81. data/lib/active_admin/orm/active_record/comments/views/active_admin_comments.rb +1 -1
  82. data/lib/active_admin/orm/active_record/comments.rb +8 -8
  83. data/lib/active_admin/pundit_adapter.rb +20 -14
  84. data/lib/active_admin/resource/action_items.rb +2 -2
  85. data/lib/active_admin/resource/attributes.rb +8 -1
  86. data/lib/active_admin/resource/belongs_to.rb +0 -1
  87. data/lib/active_admin/resource_controller/decorators.rb +1 -1
  88. data/lib/active_admin/resource_controller/streaming.rb +1 -1
  89. data/lib/active_admin/version.rb +1 -1
  90. data/lib/active_admin/view_helpers/auto_link_helper.rb +1 -1
  91. data/lib/active_admin/view_helpers/display_helper.rb +10 -3
  92. data/lib/active_admin/views/components/active_admin_form.rb +14 -6
  93. data/lib/active_admin/views/components/paginated_collection.rb +4 -1
  94. data/lib/active_admin/views/index_as_table.rb +8 -7
  95. data/lib/active_admin/views/pages/base.rb +4 -3
  96. data/lib/active_admin/views/pages/index.rb +1 -1
  97. data/lib/active_admin/views/pages/show.rb +1 -7
  98. data/lib/active_admin.rb +5 -3
  99. data/lib/generators/active_admin/install/templates/active_admin.rb.erb +19 -2
  100. data/vendor/assets/javascripts/jquery-ui/data.js +12 -8
  101. data/vendor/assets/javascripts/jquery-ui/disable-selection.js +10 -7
  102. data/vendor/assets/javascripts/jquery-ui/focusable.js +12 -9
  103. data/vendor/assets/javascripts/jquery-ui/form-reset-mixin.js +60 -57
  104. data/vendor/assets/javascripts/jquery-ui/form.js +15 -12
  105. data/vendor/assets/javascripts/jquery-ui/ie.js +5 -2
  106. data/vendor/assets/javascripts/jquery-ui/keycode.js +11 -7
  107. data/vendor/assets/javascripts/jquery-ui/labels.js +46 -40
  108. data/vendor/assets/javascripts/jquery-ui/plugin.js +5 -2
  109. data/vendor/assets/javascripts/jquery-ui/position.js +30 -17
  110. data/vendor/assets/javascripts/jquery-ui/safe-active-element.js +6 -2
  111. data/vendor/assets/javascripts/jquery-ui/safe-blur.js +6 -2
  112. data/vendor/assets/javascripts/jquery-ui/scroll-parent.js +10 -7
  113. data/vendor/assets/javascripts/jquery-ui/tabbable.js +11 -8
  114. data/vendor/assets/javascripts/jquery-ui/unique-id.js +10 -7
  115. data/vendor/assets/javascripts/jquery-ui/version.js +6 -3
  116. data/vendor/assets/javascripts/jquery-ui/widget.js +53 -30
  117. data/vendor/assets/javascripts/jquery-ui/widgets/button.js +87 -24
  118. data/vendor/assets/javascripts/jquery-ui/widgets/checkboxradio.js +276 -273
  119. data/vendor/assets/javascripts/jquery-ui/widgets/controlgroup.js +15 -11
  120. data/vendor/assets/javascripts/jquery-ui/widgets/datepicker.js +182 -62
  121. data/vendor/assets/javascripts/jquery-ui/widgets/dialog.js +53 -36
  122. data/vendor/assets/javascripts/jquery-ui/widgets/draggable.js +28 -19
  123. data/vendor/assets/javascripts/jquery-ui/widgets/mouse.js +22 -11
  124. data/vendor/assets/javascripts/jquery-ui/widgets/resizable.js +47 -26
  125. data/vendor/assets/javascripts/jquery-ui/widgets/sortable.js +186 -125
  126. data/vendor/assets/javascripts/jquery-ui/widgets/tabs.js +20 -20
  127. metadata +34 -79
  128. data/docs/.gitignore +0 -1
  129. data/docs/0-installation.md +0 -142
  130. data/docs/1-general-configuration.md +0 -224
  131. data/docs/10-custom-pages.md +0 -150
  132. data/docs/11-decorators.md +0 -70
  133. data/docs/12-arbre-components.md +0 -214
  134. data/docs/13-authorization-adapter.md +0 -285
  135. data/docs/14-gotchas.md +0 -138
  136. data/docs/2-resource-customization.md +0 -475
  137. data/docs/3-index-pages/custom-index.md +0 -35
  138. data/docs/3-index-pages/index-as-block.md +0 -19
  139. data/docs/3-index-pages/index-as-blog.md +0 -69
  140. data/docs/3-index-pages/index-as-grid.md +0 -27
  141. data/docs/3-index-pages/index-as-table.md +0 -234
  142. data/docs/3-index-pages.md +0 -328
  143. data/docs/4-csv-format.md +0 -74
  144. data/docs/5-forms.md +0 -237
  145. data/docs/6-show-pages.md +0 -93
  146. data/docs/7-sidebars.md +0 -75
  147. data/docs/8-custom-actions.md +0 -177
  148. data/docs/9-batch-actions.md +0 -237
  149. data/docs/CNAME +0 -1
  150. data/docs/Gemfile +0 -4
  151. data/docs/Gemfile.lock +0 -283
  152. data/docs/README.md +0 -24
  153. data/docs/_config.yml +0 -4
  154. data/docs/_includes/footer.html +0 -8
  155. data/docs/_includes/google-analytics.html +0 -16
  156. data/docs/_includes/head.html +0 -7
  157. data/docs/_includes/toc.html +0 -98
  158. data/docs/_includes/top-menu.html +0 -17
  159. data/docs/_layouts/default.html +0 -21
  160. data/docs/documentation.md +0 -60
  161. data/docs/images/activeadmin.png +0 -0
  162. data/docs/images/code-header.png +0 -0
  163. data/docs/images/divider.png +0 -0
  164. data/docs/images/features.png +0 -0
  165. data/docs/images/tidelift.svg +0 -14
  166. data/docs/index.html +0 -226
  167. data/docs/stylesheets/main.css +0 -1205
  168. data/lib/active_admin/deprecation.rb +0 -11
  169. data/lib/ransack_ext.rb +0 -21
  170. data/vendor/assets/javascripts/jquery-ui/escape-selector.js +0 -23
@@ -3,8 +3,8 @@ module ActiveAdmin
3
3
  module Filters
4
4
 
5
5
  class Disabled < RuntimeError
6
- def initialize
7
- super "Can't remove a filter when filters are disabled. Enable filters with 'config.filters = true'"
6
+ def initialize(action)
7
+ super "Cannot #{action} a filter when filters are disabled. Enable filters with 'config.filters = true'"
8
8
  end
9
9
  end
10
10
 
@@ -61,7 +61,7 @@ module ActiveAdmin
61
61
  #
62
62
  # @param [Symbol] attributes The attributes to not filter on
63
63
  def remove_filter(*attributes)
64
- raise Disabled unless filters_enabled?
64
+ raise Disabled, "remove" unless filters_enabled?
65
65
 
66
66
  attributes.each { |attribute| (@filters_to_remove ||= []) << attribute.to_sym }
67
67
  end
@@ -73,7 +73,7 @@ module ActiveAdmin
73
73
  # @param [Hash] options The set of options that are passed through to
74
74
  # ransack for the field definition.
75
75
  def add_filter(attribute, options = {})
76
- raise Disabled unless filters_enabled?
76
+ raise Disabled, "add" unless filters_enabled?
77
77
 
78
78
  (@filters ||= {})[attribute.to_sym] = options
79
79
  end
@@ -95,7 +95,7 @@ module ActiveAdmin
95
95
  contents = without_wrapper { inputs(options, &form_block) }
96
96
  contents ||= "".html_safe
97
97
 
98
- js = new_record ? js_for_has_many(options[:class], &form_block) : ""
98
+ js = new_record ? js_for_has_many(&form_block) : ""
99
99
  contents << js
100
100
  end
101
101
 
@@ -159,14 +159,13 @@ module ActiveAdmin
159
159
  end
160
160
 
161
161
  # Capture the ADD JS
162
- def js_for_has_many(class_string, &form_block)
162
+ def js_for_has_many(&form_block)
163
163
  assoc_name = assoc_klass.model_name
164
- placeholder = "NEW_#{assoc_name.to_s.underscore.upcase.gsub(/\//, '_')}_RECORD"
165
- opts = {
164
+ placeholder = "NEW_#{assoc_name.to_s.underscore.upcase.tr('/', '_')}_RECORD"
165
+ opts = options.merge(
166
166
  for: [assoc, assoc_klass.new],
167
- class: class_string,
168
167
  for_options: { child_index: placeholder }
169
- }
168
+ )
170
169
  html = template.capture { __getobj__.send(:inputs_for_nested_attributes, opts, &form_block) }
171
170
  text = new_record.is_a?(String) ? new_record : I18n.t("active_admin.has_many_new", model: assoc_name.human)
172
171
 
@@ -9,7 +9,7 @@
9
9
  # include Base
10
10
  # include Base::SearchMethodSelect
11
11
  #
12
- # filter :equals, :greater_than, :less_than
12
+ # filter :eq, :gt, :lt
13
13
  # end
14
14
  #
15
15
  module ActiveAdmin
@@ -65,7 +65,7 @@ module ActiveAdmin
65
65
 
66
66
  def filter_options
67
67
  filters.collect do |filter|
68
- [I18n.t("active_admin.filters.predicates.#{filter}"), "#{method}_#{filter}"]
68
+ [I18n.t("ransack.predicates.#{filter}").capitalize, "#{method}_#{filter}"]
69
69
  end
70
70
  end
71
71
 
@@ -15,12 +15,12 @@ module ActiveAdmin
15
15
  end
16
16
 
17
17
  def gt_input_name
18
- column && column.type == :date ? "#{method}_gteq" : "#{method}_gteq_datetime"
18
+ "#{method}_gteq"
19
19
  end
20
20
  alias :input_name :gt_input_name
21
21
 
22
22
  def lt_input_name
23
- column && column.type == :date ? "#{method}_lteq" : "#{method}_lteq_datetime"
23
+ "#{method}_lteq"
24
24
  end
25
25
 
26
26
  def input_html_options
@@ -6,7 +6,7 @@ module ActiveAdmin
6
6
  include Base
7
7
  include Base::SearchMethodSelect
8
8
 
9
- filter :equals, :greater_than, :less_than
9
+ filter :eq, :gt, :lt
10
10
  end
11
11
  end
12
12
  end
@@ -15,9 +15,7 @@ module ActiveAdmin
15
15
  if searchable_has_many_through?
16
16
  "#{reflection.through_reflection.name}_#{reflection.foreign_key}"
17
17
  else
18
- name = method.to_s
19
- name.concat "_#{reflection.association_primary_key}" if reflection_searchable?
20
- name
18
+ reflection_searchable? ? "#{method}_#{reflection.association_primary_key}" : method.to_s
21
19
  end
22
20
  end
23
21
 
@@ -43,6 +41,8 @@ module ActiveAdmin
43
41
  else
44
42
  super
45
43
  end
44
+ rescue ActiveRecord::QueryCanceled => error
45
+ raise ActiveRecord::QueryCanceled.new "#{error.message.strip} while querying the values for the ActiveAdmin :#{method} filter"
46
46
  end
47
47
 
48
48
  def pluck_column
@@ -6,7 +6,7 @@ module ActiveAdmin
6
6
  include Base
7
7
  include Base::SearchMethodSelect
8
8
 
9
- filter :contains, :equals, :starts_with, :ends_with
9
+ filter :cont, :eq, :start, :end
10
10
 
11
11
  # If the filter method includes a search condition, build a normal string search field.
12
12
  # Else, build a search field with a companion dropdown to choose a search condition from.
@@ -48,6 +48,7 @@ module ActiveAdmin
48
48
  # menu.add parent: 'Dashboard', label: 'My Child Dashboard'
49
49
  #
50
50
  def add(options)
51
+ options = options.dup # Make sure parameter is not modified
51
52
  parent_chain = Array.wrap(options.delete(:parent))
52
53
 
53
54
  item = if parent = parent_chain.shift
@@ -28,7 +28,7 @@ module ActiveAdmin
28
28
  class Namespace
29
29
  class << self
30
30
  def setting(name, default)
31
- Deprecation.warn "This method does not do anything and will be removed."
31
+ ActiveAdmin.deprecator.warn "This method does not do anything and will be removed."
32
32
  end
33
33
  end
34
34
 
@@ -60,7 +60,7 @@ module ActiveAdmin
60
60
  settings.respond_to?(method) ? settings.send(method, *args) : super
61
61
  end
62
62
 
63
- # Register a resource into this namespace. The preffered method to access this is to
63
+ # Register a resource into this namespace. The preferred method to access this is to
64
64
  # use the global registration ActiveAdmin.register which delegates to the proper
65
65
  # namespace instance.
66
66
  def register(resource_class, options = {}, &block)
@@ -72,7 +72,7 @@ module ActiveAdmin
72
72
  reset_menu!
73
73
 
74
74
  # Dispatch a registration event
75
- ActiveSupport::Notifications.instrument ActiveAdmin::Resource::RegisterEvent, config
75
+ ActiveSupport::Notifications.instrument ActiveAdmin::Resource::RegisterEvent, { active_admin_resource: config }
76
76
 
77
77
  # Return the config
78
78
  config
@@ -119,7 +119,7 @@ module ActiveAdmin
119
119
  :title,
120
120
  :email,
121
121
  ]
122
- register :filter_method_for_large_association, "_starts_with"
122
+ register :filter_method_for_large_association, "_start"
123
123
 
124
124
  # Switch between asset pipeline and webpacker assets
125
125
  register :use_webpacker, false
@@ -28,5 +28,13 @@ module ActiveAdmin
28
28
  self.resource_type = self.class.resource_type(resource)
29
29
  end
30
30
 
31
+ def self.ransackable_attributes(auth_object = nil)
32
+ authorizable_ransackable_attributes
33
+ end
34
+
35
+ def self.ransackable_associations(auth_object = nil)
36
+ authorizable_ransackable_associations
37
+ end
38
+
31
39
  end
32
40
  end
@@ -36,7 +36,7 @@ module ActiveAdmin
36
36
 
37
37
  text_node paginate @comments
38
38
 
39
- if authorized?(ActiveAdmin::Auth::CREATE, ActiveAdmin::Comment)
39
+ if authorized?(ActiveAdmin::Auth::NEW, ActiveAdmin::Comment)
40
40
  build_comment_form
41
41
  end
42
42
  end
@@ -72,15 +72,15 @@ ActiveAdmin.after_load do |app|
72
72
  redirect_back fallback_location: active_admin_root
73
73
  end
74
74
  end
75
+ end
75
76
 
76
- def destroy
77
- destroy! do |success, failure|
78
- success.html do
79
- redirect_back fallback_location: active_admin_root
80
- end
81
- failure.html do
82
- redirect_back fallback_location: active_admin_root
83
- end
77
+ def destroy
78
+ destroy! do |success, failure|
79
+ success.html do
80
+ redirect_back fallback_location: active_admin_root
81
+ end
82
+ failure.html do
83
+ redirect_back fallback_location: active_admin_root
84
84
  end
85
85
  end
86
86
  end
@@ -31,22 +31,19 @@ module ActiveAdmin
31
31
  end
32
32
 
33
33
  def retrieve_policy(subject)
34
- Pundit.policy!(user, namespace(policy_target(subject)))
35
- rescue Pundit::NotDefinedError => e
36
- if (policy = compat_policy(subject))
34
+ target = policy_target(subject)
35
+ if (policy = policy(namespace(target)) || compat_policy(subject))
37
36
  policy
38
37
  elsif default_policy_class
39
- default_policy(user, subject)
38
+ default_policy(subject)
40
39
  else
41
- raise e
40
+ raise Pundit::NotDefinedError, "unable to find a compatible policy for `#{target}`"
42
41
  end
43
42
  end
44
43
 
45
44
  def format_action(action, subject)
46
- # https://github.com/varvet/pundit/blob/master/lib/generators/pundit/install/templates/application_policy.rb
45
+ # https://github.com/varvet/pundit/blob/main/lib/generators/pundit/install/templates/application_policy.rb
47
46
  case action
48
- when Auth::CREATE then :create?
49
- when Auth::UPDATE then :update?
50
47
  when Auth::READ then subject.is_a?(Class) ? :index? : :show?
51
48
  when Auth::DESTROY then subject.is_a?(Class) ? :destroy_all? : :destroy?
52
49
  else "#{action}?"
@@ -71,15 +68,16 @@ module ActiveAdmin
71
68
  # This fallback might be removed in future versions of ActiveAdmin, so
72
69
  # pundit_adapter search will work consistently with provided namespaces
73
70
  def compat_policy(subject)
71
+ return unless default_policy_namespace
72
+
74
73
  target = policy_target(subject)
75
74
 
76
- return unless default_policy_namespace &&
77
- target.class.to_s.include?(default_policy_module) &&
78
- (policy = Pundit.policy(user, target))
75
+ return unless target.class.to_s.include?(default_policy_module) &&
76
+ (policy = policy(target))
79
77
 
80
78
  policy_name = policy.class.to_s
81
79
 
82
- Deprecation.warn "You have `pundit_policy_namespace` configured as `#{default_policy_namespace}`, " \
80
+ ActiveAdmin.deprecator.warn "You have `pundit_policy_namespace` configured as `#{default_policy_namespace}`, " \
83
81
  "but ActiveAdmin was unable to find policy #{default_policy_module}::#{policy_name}. " \
84
82
  "#{policy_name} will be used instead. " \
85
83
  "This behavior will be removed in future versions of ActiveAdmin. " \
@@ -89,7 +87,7 @@ module ActiveAdmin
89
87
  end
90
88
 
91
89
  def namespace(object)
92
- if default_policy_namespace && !object.class.to_s.match?(/^#{default_policy_module}::/)
90
+ if default_policy_namespace && !object.class.to_s.start_with?("#{default_policy_module}::")
93
91
  [default_policy_namespace.to_sym, object]
94
92
  else
95
93
  object
@@ -100,7 +98,7 @@ module ActiveAdmin
100
98
  ActiveAdmin.application.pundit_default_policy && ActiveAdmin.application.pundit_default_policy.constantize
101
99
  end
102
100
 
103
- def default_policy(user, subject)
101
+ def default_policy(subject)
104
102
  default_policy_class.new(user, subject)
105
103
  end
106
104
 
@@ -112,6 +110,14 @@ module ActiveAdmin
112
110
  default_policy_namespace.to_s.camelize
113
111
  end
114
112
 
113
+ def policy(target)
114
+ policies[target] ||= Pundit.policy(user, target)
115
+ end
116
+
117
+ def policies
118
+ @policies ||= {}
119
+ end
120
+
115
121
  end
116
122
 
117
123
  end
@@ -65,7 +65,7 @@ module ActiveAdmin
65
65
  # Adds the default New link on index
66
66
  def add_default_new_action_item
67
67
  add_action_item :new, only: :index do
68
- if controller.action_methods.include?("new") && authorized?(ActiveAdmin::Auth::CREATE, active_admin_config.resource_class)
68
+ if controller.action_methods.include?("new") && authorized?(ActiveAdmin::Auth::NEW, active_admin_config.resource_class)
69
69
  localizer = ActiveAdmin::Localizers.resource(active_admin_config)
70
70
  link_to localizer.t(:new_model), new_resource_path
71
71
  end
@@ -75,7 +75,7 @@ module ActiveAdmin
75
75
  # Adds the default Edit link on show
76
76
  def add_default_edit_action_item
77
77
  add_action_item :edit, only: :show do
78
- if controller.action_methods.include?("edit") && authorized?(ActiveAdmin::Auth::UPDATE, resource)
78
+ if controller.action_methods.include?("edit") && authorized?(ActiveAdmin::Auth::EDIT, resource)
79
79
  localizer = ActiveAdmin::Localizers.resource(active_admin_config)
80
80
  link_to localizer.t(:edit_model), edit_resource_path(resource)
81
81
  end
@@ -37,7 +37,14 @@ module ActiveAdmin
37
37
  end
38
38
 
39
39
  def counter_cache_col?(c)
40
- c.name.end_with?("_count")
40
+ # This helper is called inside a loop. Let's memoize the result.
41
+ @counter_cache_columns ||= begin
42
+ resource_class.reflect_on_all_associations(:has_many)
43
+ .select(&:has_cached_counter?)
44
+ .map(&:counter_cache_column)
45
+ end
46
+
47
+ @counter_cache_columns.include?(c.name)
41
48
  end
42
49
 
43
50
  def filtered_col?(c)
@@ -1,5 +1,4 @@
1
1
  # frozen_string_literal: true
2
- require "active_admin/resource"
3
2
 
4
3
  module ActiveAdmin
5
4
  class Resource
@@ -61,7 +61,7 @@ module ActiveAdmin
61
61
  def self.wrap!(parent, name)
62
62
  ::Class.new parent do
63
63
  delegate :reorder, :page, :current_page, :total_pages, :limit_value,
64
- :total_count, :total_pages, :offset, :to_key, :group_values,
64
+ :total_count, :offset, :to_key, :group_values,
65
65
  :except, :find_each, :ransack, to: :object
66
66
 
67
67
  define_singleton_method(:name) { name }
@@ -31,7 +31,7 @@ module ActiveAdmin
31
31
  end
32
32
 
33
33
  def csv_filename
34
- "#{resource_collection_name.to_s.gsub('_', '-')}-#{Time.zone.now.to_date.to_formatted_s(:default)}.csv"
34
+ "#{resource_collection_name.to_s.gsub('_', '-')}-#{Time.zone.now.to_date.to_s}.csv"
35
35
  end
36
36
 
37
37
  def stream_csv
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ActiveAdmin
3
- VERSION = "2.12.0"
3
+ VERSION = "3.3.0"
4
4
  end
@@ -29,7 +29,7 @@ module ActiveAdmin
29
29
  authorized?(ActiveAdmin::Auth::READ, resource)
30
30
  url_for config.route_instance_path resource, url_options
31
31
  elsif config.controller.action_methods.include?("edit") &&
32
- authorized?(ActiveAdmin::Auth::UPDATE, resource)
32
+ authorized?(ActiveAdmin::Auth::EDIT, resource)
33
33
  url_for config.route_edit_instance_path resource, url_options
34
34
  end
35
35
  end
@@ -24,7 +24,14 @@ module ActiveAdmin
24
24
  # Attempts to call any known display name methods on the resource.
25
25
  # See the setting in `application.rb` for the list of methods and their priority.
26
26
  def display_name(resource)
27
- ERB::Util.html_escape(render_in_context(resource, display_name_method_for(resource))) unless resource.nil?
27
+ unless resource.nil?
28
+ result = render_in_context(resource, display_name_method_for(resource))
29
+ if result.to_s&.strip&.present?
30
+ ERB::Util.html_escape(result)
31
+ else
32
+ ERB::Util.html_escape(render_in_context(resource, DISPLAY_NAME_FALLBACK))
33
+ end
34
+ end
28
35
  end
29
36
 
30
37
  # Looks up and caches the first available display name method.
@@ -101,8 +108,8 @@ module ActiveAdmin
101
108
  when TrueClass, FalseClass
102
109
  true
103
110
  else
104
- if resource.class.respond_to? :columns_hash
105
- column = resource.class.columns_hash[attr.to_s] and column.type == :boolean
111
+ if resource.class.respond_to? :attribute_types
112
+ resource.class.attribute_types[attr.to_s].is_a?(ActiveModel::Type::Boolean)
106
113
  end
107
114
  end
108
115
  end
@@ -102,10 +102,6 @@ module ActiveAdmin
102
102
  form_builder.object
103
103
  end
104
104
 
105
- def form_buffers
106
- raise "'form_buffers' has been removed from ActiveAdmin::FormBuilder, please read https://github.com/activeadmin/activeadmin/blob/master/docs/5-forms.md for details."
107
- end
108
-
109
105
  private
110
106
 
111
107
  def create_another_checkbox
@@ -131,12 +127,24 @@ module ActiveAdmin
131
127
  html_options[:class] ||= "inputs"
132
128
  legend = args.shift if args.first.is_a?(::String)
133
129
  legend = html_options.delete(:name) if html_options.key?(:name)
134
- legend_tag = legend ? "<legend><span>#{legend}</span></legend>" : ""
135
- fieldset_attrs = html_options.map { |k, v| %Q{#{k}="#{v}"} }.join(" ")
130
+ legend_tag = legend ? helpers.tag.legend(helpers.tag.span(legend), class: "fieldset-title") : ""
131
+ fieldset_attrs = tag_attributes html_options
136
132
  @opening_tag = "<fieldset #{fieldset_attrs}>#{legend_tag}<ol>"
137
133
  @closing_tag = "</ol></fieldset>"
138
134
  super(*(args << html_options), &block)
139
135
  end
136
+
137
+ private
138
+
139
+ def tag_attributes(html_options)
140
+ if Rails::VERSION::MAJOR <= 6
141
+ # Reimplement tag.attributes to backport support for Rails 6.1.
142
+ # TODO: this can be removed when support for Rails 6.x is dropped
143
+ helpers.tag.tag_options(html_options.to_h).to_s.strip.html_safe
144
+ else
145
+ helpers.tag.attributes html_options
146
+ end
147
+ end
140
148
  end
141
149
 
142
150
  class SemanticActionsProxy < FormtasticProxy
@@ -103,7 +103,10 @@ module ActiveAdmin
103
103
  # you pass in the :total_pages option. We issue a query to determine
104
104
  # if there is another page or not, but the limit/offset make this
105
105
  # query fast.
106
- offset = collection.offset(collection.current_page * collection.limit_value).limit(1).count
106
+ offset_scope = collection.offset(collection.current_page * collection.limit_value)
107
+ # Support array collections. Kaminari::PaginatableArray does not respond to except
108
+ offset_scope = offset_scope.except(:select, :order) if offset_scope.respond_to?(:except)
109
+ offset = offset_scope.limit(1).count
107
110
  options[:total_pages] = collection.current_page + offset
108
111
  options[:right] = 0
109
112
  end
@@ -291,9 +291,14 @@ module ActiveAdmin
291
291
  end
292
292
 
293
293
  # Display a column for the id
294
- def id_column
294
+ def id_column(*args)
295
295
  raise "#{resource_class.name} has no primary_key!" unless resource_class.primary_key
296
- column(resource_class.human_attribute_name(resource_class.primary_key), sortable: resource_class.primary_key) do |resource|
296
+
297
+ options = args.extract_options!
298
+ title = args[0].presence || resource_class.human_attribute_name(resource_class.primary_key)
299
+ sortable = options.fetch(:sortable, resource_class.primary_key)
300
+
301
+ column(title, sortable: sortable) do |resource|
297
302
  if controller.action_methods.include?("show")
298
303
  link_to resource.id, resource_path(resource), class: "resource_id_link"
299
304
  elsif controller.action_methods.include?("edit")
@@ -304,10 +309,6 @@ module ActiveAdmin
304
309
  end
305
310
  end
306
311
 
307
- def default_actions
308
- raise "`default_actions` is no longer provided in ActiveAdmin 1.x. Use `actions` instead."
309
- end
310
-
311
312
  # Add links to perform actions.
312
313
  #
313
314
  # ```ruby
@@ -377,7 +378,7 @@ module ActiveAdmin
377
378
  if controller.action_methods.include?("show") && authorized?(ActiveAdmin::Auth::READ, resource)
378
379
  item localizer.t(:view), resource_path(resource), class: "view_link #{options[:css_class]}", title: localizer.t(:view)
379
380
  end
380
- if controller.action_methods.include?("edit") && authorized?(ActiveAdmin::Auth::UPDATE, resource)
381
+ if controller.action_methods.include?("edit") && authorized?(ActiveAdmin::Auth::EDIT, resource)
381
382
  item localizer.t(:edit), edit_resource_path(resource), class: "edit_link #{options[:css_class]}", title: localizer.t(:edit)
382
383
  end
383
384
  if controller.action_methods.include?("destroy") && authorized?(ActiveAdmin::Auth::DESTROY, resource)
@@ -38,8 +38,8 @@ module ActiveAdmin
38
38
  text_node(meta(name: name, content: content))
39
39
  end
40
40
 
41
- active_admin_application.javascripts.each do |path|
42
- javascript_tag = active_admin_namespace.use_webpacker ? javascript_pack_tag(path) : javascript_include_tag(path)
41
+ active_admin_application.javascripts.each do |path, options|
42
+ javascript_tag = active_admin_namespace.use_webpacker ? javascript_pack_tag(path, **options) : javascript_include_tag(path, **options)
43
43
  text_node(javascript_tag)
44
44
  end
45
45
 
@@ -49,7 +49,8 @@ module ActiveAdmin
49
49
  text_node(favicon_tag)
50
50
  end
51
51
 
52
- text_node csrf_meta_tag
52
+ text_node csrf_meta_tags
53
+ text_node csp_meta_tag
53
54
  end
54
55
  end
55
56
 
@@ -112,7 +112,7 @@ module ActiveAdmin
112
112
 
113
113
  def render_blank_slate
114
114
  blank_slate_content = I18n.t("active_admin.blank_slate.content", resource_name: active_admin_config.plural_resource_label)
115
- if controller.action_methods.include?("new") && authorized?(ActiveAdmin::Auth::CREATE, active_admin_config.resource_class)
115
+ if controller.action_methods.include?("new") && authorized?(ActiveAdmin::Auth::NEW, active_admin_config.resource_class)
116
116
  blank_slate_content = [blank_slate_content, blank_slate_link].compact.join(" ")
117
117
  end
118
118
  insert_tag(view_factory.blank_slate, blank_slate_content)
@@ -40,13 +40,7 @@ module ActiveAdmin
40
40
  protected
41
41
 
42
42
  def default_title
43
- title = display_name(resource)
44
-
45
- if title.blank?
46
- title = "#{active_admin_config.resource_label} ##{resource.id}"
47
- end
48
-
49
- title
43
+ display_name(resource)
50
44
  end
51
45
 
52
46
  module DefaultMainContent
data/lib/active_admin.rb CHANGED
@@ -3,7 +3,6 @@ require "active_support/core_ext"
3
3
  require "set"
4
4
 
5
5
  require "ransack"
6
- require "ransack_ext"
7
6
  require "kaminari"
8
7
  require "formtastic"
9
8
  require "formtastic_i18n"
@@ -27,7 +26,6 @@ module ActiveAdmin
27
26
  autoload :ControllerAction, "active_admin/controller_action"
28
27
  autoload :CSVBuilder, "active_admin/csv_builder"
29
28
  autoload :Dependency, "active_admin/dependency"
30
- autoload :Deprecation, "active_admin/deprecation"
31
29
  autoload :Devise, "active_admin/devise"
32
30
  autoload :DSL, "active_admin/dsl"
33
31
  autoload :FormBuilder, "active_admin/form_builder"
@@ -62,6 +60,10 @@ module ActiveAdmin
62
60
  @application ||= ::ActiveAdmin::Application.new
63
61
  end
64
62
 
63
+ def deprecator
64
+ @deprecator ||= ActiveSupport::Deprecation.new("4.0", "active-admin")
65
+ end
66
+
65
67
  # Gets called within the initializer
66
68
  def setup
67
69
  application.setup!
@@ -113,7 +115,7 @@ module ActiveAdmin
113
115
  private
114
116
 
115
117
  def wrap_block_for_active_support_notifications block
116
- proc { |_name, _start, _finish, _id, payload| block.call payload }
118
+ proc { |_name, _start, _finish, _id, payload| block.call payload[:active_admin_application] }
117
119
  end
118
120
 
119
121
  end
@@ -18,6 +18,23 @@ ActiveAdmin.setup do |config|
18
18
  #
19
19
  # config.site_title_image = "logo.png"
20
20
 
21
+ # == Load Paths
22
+ #
23
+ # By default Active Admin files go inside app/admin/.
24
+ # You can change this directory.
25
+ #
26
+ # eg:
27
+ # config.load_paths = [File.join(Rails.root, 'app', 'ui')]
28
+ #
29
+ # Or, you can also load more directories.
30
+ # Useful when setting namespaces with users that are not your main AdminUser entity.
31
+ #
32
+ # eg:
33
+ # config.load_paths = [
34
+ # File.join(Rails.root, 'app', 'admin'),
35
+ # File.join(Rails.root, 'app', 'cashier')
36
+ # ]
37
+
21
38
  # == Default Namespace
22
39
  #
23
40
  # Set the default namespace each administration resource
@@ -241,7 +258,7 @@ ActiveAdmin.setup do |config|
241
258
  #
242
259
  # config.namespace :admin do |admin|
243
260
  # admin.build_menu :default do |menu|
244
- # menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank }
261
+ # menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: "_blank" }
245
262
  # end
246
263
  # end
247
264
 
@@ -303,7 +320,7 @@ ActiveAdmin.setup do |config|
303
320
  # :title,
304
321
  # :email,
305
322
  # ]
306
- # config.filter_method_for_large_association = '_starts_with'
323
+ # config.filter_method_for_large_association = '_start'
307
324
 
308
325
  # == Head
309
326
  #