administrate 0.15.0 → 0.18.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.
- checksums.yaml +4 -4
- data/Rakefile +0 -2
- data/app/assets/javascripts/administrate/application.js +0 -2
- data/app/assets/stylesheets/administrate/application.scss +0 -1
- data/app/assets/stylesheets/administrate/base/_forms.scss +1 -1
- data/app/assets/stylesheets/administrate/components/_buttons.scss +12 -0
- data/app/assets/stylesheets/administrate/components/_flashes.scss +2 -2
- data/app/assets/stylesheets/administrate/library/_variables.scss +1 -1
- data/app/controllers/administrate/application_controller.rb +95 -17
- data/app/controllers/concerns/administrate/punditize.rb +4 -2
- data/app/helpers/administrate/application_helper.rb +24 -6
- data/app/views/administrate/application/_collection.html.erb +20 -24
- data/app/views/administrate/application/_collection_header_actions.html.erb +4 -0
- data/app/views/administrate/application/_collection_item_actions.html.erb +17 -0
- data/app/views/administrate/application/_flashes.html.erb +1 -0
- data/app/views/administrate/application/_form.html.erb +1 -1
- data/app/views/administrate/application/_icons.html.erb +1 -1
- data/app/views/administrate/application/_index_header.html.erb +28 -0
- data/app/views/administrate/application/_navigation.html.erb +2 -2
- data/app/views/administrate/application/_pagination.html.erb +1 -0
- data/app/views/administrate/application/edit.html.erb +1 -1
- data/app/views/administrate/application/index.html.erb +9 -29
- data/app/views/administrate/application/show.html.erb +9 -1
- data/app/views/fields/belongs_to/_index.html.erb +1 -1
- data/app/views/fields/belongs_to/_show.html.erb +1 -1
- data/app/views/fields/date/_form.html.erb +1 -3
- data/app/views/fields/date_time/_form.html.erb +1 -3
- data/app/views/fields/has_many/_index.html.erb +1 -1
- data/app/views/fields/has_one/_form.html.erb +1 -1
- data/app/views/fields/has_one/_index.html.erb +2 -1
- data/app/views/fields/has_one/_show.html.erb +3 -2
- data/app/views/fields/polymorphic/_index.html.erb +2 -1
- data/app/views/fields/polymorphic/_show.html.erb +1 -1
- data/app/views/fields/select/_form.html.erb +4 -2
- data/app/views/fields/time/_form.html.erb +2 -3
- data/app/views/fields/time/_index.html.erb +1 -1
- data/app/views/fields/time/_show.html.erb +1 -1
- data/app/views/fields/url/_index.html.erb +2 -2
- data/app/views/fields/url/_show.html.erb +2 -2
- data/config/locales/administrate.de.yml +2 -2
- data/config/locales/administrate.sl.yml +30 -0
- data/config/locales/administrate.zh-TW.yml +1 -1
- data/docs/adding_controllers_without_related_model.md +2 -4
- data/docs/authorization.md +25 -12
- data/docs/customizing_controller_actions.md +30 -7
- data/docs/customizing_dashboards.md +62 -6
- data/docs/extending_administrate.md +5 -5
- data/docs/getting_started.md +1 -1
- data/docs/guides/customising_search.md +149 -0
- data/docs/guides/hiding_dashboards_from_sidebar.md +4 -2
- data/docs/guides/scoping_has_many_relations.md +27 -0
- data/docs/guides.md +3 -1
- data/lib/administrate/base_dashboard.rb +30 -2
- data/lib/administrate/engine.rb +2 -2
- data/lib/administrate/field/associative.rb +7 -7
- data/lib/administrate/field/base.rb +4 -0
- data/lib/administrate/field/belongs_to.rb +4 -0
- data/lib/administrate/field/deferred.rb +4 -0
- data/lib/administrate/field/has_one.rb +4 -0
- data/lib/administrate/field/select.rb +4 -0
- data/lib/administrate/field/time.rb +11 -0
- data/lib/administrate/field/url.rb +4 -0
- data/lib/administrate/namespace.rb +1 -1
- data/lib/administrate/not_authorized_error.rb +18 -0
- data/lib/administrate/order.rb +35 -5
- data/lib/administrate/page/base.rb +4 -0
- data/lib/administrate/page/form.rb +9 -2
- data/lib/administrate/resource_resolver.rb +1 -1
- data/lib/administrate/search.rb +21 -17
- data/lib/administrate/version.rb +1 -1
- data/lib/administrate/view_generator.rb +1 -1
- data/lib/administrate.rb +18 -0
- data/lib/generators/administrate/dashboard/dashboard_generator.rb +15 -2
- data/lib/generators/administrate/dashboard/templates/controller.rb.erb +2 -2
- data/lib/generators/administrate/install/templates/application_controller.rb.erb +1 -1
- metadata +11 -49
- data/app/assets/javascripts/administrate/components/date_time_picker.js +0 -14
- data/config/i18n-tasks.yml +0 -18
- data/config/routes.rb +0 -2
- data/config/unicorn.rb +0 -25
@@ -0,0 +1,27 @@
|
|
1
|
+
---
|
2
|
+
title: Scoping HasMany Relations
|
3
|
+
---
|
4
|
+
|
5
|
+
To show a subset of a has_many relationship, create a new [has_many](https://apidock.com/rails/ActiveRecord/Associations/ClassMethods/has_many) relationship in your model (using the `scope` argument) and add it to the model's dashboard.
|
6
|
+
|
7
|
+
## Creating a scoped has_many relationship
|
8
|
+
|
9
|
+
Models can define subsets of a `has_many` relationship by passing a callable (i.e. proc or lambda) as its second argument.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class Customer < ApplicationRecord
|
13
|
+
has_many :orders
|
14
|
+
has_many :processed_orders, ->{ where(processed: true) }, class_name: "Order"
|
15
|
+
```
|
16
|
+
|
17
|
+
Since ActiveRecord infers the class name from the first argument, the new `has_many` relation needs to specify the model using the `class_name` option.
|
18
|
+
|
19
|
+
## Add new relationship to dashboard
|
20
|
+
|
21
|
+
Your new scoped relation can be used in the dashboard just like the original `HasMany`. Notice the new field needs to specifiy the class name as an option like you did in the model.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
ATTRIBUTE_TYPES = {
|
25
|
+
orders: Field::HasMany,
|
26
|
+
processed_orders: Field::HasMany.with_options(class_name: 'Order')
|
27
|
+
```
|
data/docs/guides.md
CHANGED
@@ -2,4 +2,6 @@
|
|
2
2
|
title: Guides
|
3
3
|
---
|
4
4
|
|
5
|
-
|
5
|
+
- [Hiding Dashboards from the Sidebar](./guides/hiding_dashboards_from_sidebar)
|
6
|
+
- [Customising the search](./guides/customising_search)
|
7
|
+
- [Scoping HasMany Relations](./guides/scoping_has_many_relations.md)
|
@@ -50,8 +50,16 @@ module Administrate
|
|
50
50
|
attribute_types.keys
|
51
51
|
end
|
52
52
|
|
53
|
-
def form_attributes
|
54
|
-
self.class::FORM_ATTRIBUTES
|
53
|
+
def form_attributes(action = nil)
|
54
|
+
specific_form_attributes_for(action) || self.class::FORM_ATTRIBUTES
|
55
|
+
end
|
56
|
+
|
57
|
+
def specific_form_attributes_for(action)
|
58
|
+
return unless action
|
59
|
+
|
60
|
+
cname = "FORM_ATTRIBUTES_#{action.upcase}"
|
61
|
+
|
62
|
+
self.class.const_get(cname) if self.class.const_defined?(cname)
|
55
63
|
end
|
56
64
|
|
57
65
|
def permitted_attributes
|
@@ -71,6 +79,12 @@ module Administrate
|
|
71
79
|
self.class::COLLECTION_ATTRIBUTES
|
72
80
|
end
|
73
81
|
|
82
|
+
def search_attributes
|
83
|
+
attribute_types.keys.select do |attribute|
|
84
|
+
attribute_types[attribute].searchable?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
74
88
|
def display_resource(resource)
|
75
89
|
"#{resource.class} ##{resource.id}"
|
76
90
|
end
|
@@ -80,9 +94,15 @@ module Administrate
|
|
80
94
|
end
|
81
95
|
|
82
96
|
def item_includes
|
97
|
+
# Deprecated, internal usage has moved to #item_associations
|
98
|
+
Administrate.warn_of_deprecated_method(self.class, :item_includes)
|
83
99
|
attribute_includes(show_page_attributes)
|
84
100
|
end
|
85
101
|
|
102
|
+
def item_associations
|
103
|
+
attribute_associated(show_page_attributes)
|
104
|
+
end
|
105
|
+
|
86
106
|
private
|
87
107
|
|
88
108
|
def attribute_not_found_message(attr)
|
@@ -90,6 +110,14 @@ module Administrate
|
|
90
110
|
end
|
91
111
|
|
92
112
|
def attribute_includes(attributes)
|
113
|
+
attributes.map do |key|
|
114
|
+
field = attribute_type_for(key)
|
115
|
+
|
116
|
+
key if field.eager_load?
|
117
|
+
end.compact
|
118
|
+
end
|
119
|
+
|
120
|
+
def attribute_associated(attributes)
|
93
121
|
attributes.map do |key|
|
94
122
|
field = attribute_type_for(key)
|
95
123
|
|
data/lib/administrate/engine.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require "datetime_picker_rails"
|
2
1
|
require "jquery-rails"
|
3
2
|
require "kaminari"
|
4
|
-
require "momentjs-rails"
|
5
3
|
require "sassc-rails"
|
6
4
|
require "selectize-rails"
|
7
5
|
require "sprockets/railtie"
|
8
6
|
|
7
|
+
require "administrate/namespace/resource"
|
8
|
+
require "administrate/not_authorized_error"
|
9
9
|
require "administrate/page/form"
|
10
10
|
require "administrate/page/show"
|
11
11
|
require "administrate/page/collection"
|
@@ -12,7 +12,7 @@ module Administrate
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def self.associated_class_name(resource_class, attr)
|
15
|
-
|
15
|
+
associated_class(resource_class, attr).name
|
16
16
|
end
|
17
17
|
|
18
18
|
def self.reflection(resource_class, attr)
|
@@ -31,12 +31,6 @@ module Administrate
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
private
|
35
|
-
|
36
|
-
def associated_dashboard
|
37
|
-
"#{associated_class_name}Dashboard".constantize.new
|
38
|
-
end
|
39
|
-
|
40
34
|
def associated_class_name
|
41
35
|
if option_given?(:class_name)
|
42
36
|
deprecated_option(:class_name)
|
@@ -48,6 +42,12 @@ module Administrate
|
|
48
42
|
end
|
49
43
|
end
|
50
44
|
|
45
|
+
private
|
46
|
+
|
47
|
+
def associated_dashboard
|
48
|
+
"#{associated_class_name}Dashboard".constantize.new
|
49
|
+
end
|
50
|
+
|
51
51
|
def primary_key
|
52
52
|
if option_given?(:primary_key)
|
53
53
|
deprecated_option(:primary_key)
|
@@ -3,6 +3,17 @@ require_relative "base"
|
|
3
3
|
module Administrate
|
4
4
|
module Field
|
5
5
|
class Time < Base
|
6
|
+
def time
|
7
|
+
return I18n.localize(data, format: format) if options[:format]
|
8
|
+
|
9
|
+
data.strftime("%I:%M%p")
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def format
|
15
|
+
options[:format]
|
16
|
+
end
|
6
17
|
end
|
7
18
|
end
|
8
19
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Administrate
|
2
|
+
class NotAuthorizedError < StandardError
|
3
|
+
def initialize(action:, resource:)
|
4
|
+
@action = action
|
5
|
+
@resource = resource
|
6
|
+
|
7
|
+
case resource
|
8
|
+
when Module, String, Symbol
|
9
|
+
super("Not allowed to perform #{action.inspect} on #{resource.inspect}")
|
10
|
+
else
|
11
|
+
super(
|
12
|
+
"Not allowed to perform #{action.inspect} on the given " +
|
13
|
+
resource.class.name
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/administrate/order.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
module Administrate
|
2
2
|
class Order
|
3
|
-
def initialize(attribute = nil, direction = nil)
|
3
|
+
def initialize(attribute = nil, direction = nil, association_attribute: nil)
|
4
4
|
@attribute = attribute
|
5
5
|
@direction = sanitize_direction(direction)
|
6
|
+
@association_attribute = association_attribute
|
6
7
|
end
|
7
8
|
|
8
9
|
def apply(relation)
|
@@ -12,7 +13,7 @@ module Administrate
|
|
12
13
|
order = "#{relation.table_name}.#{attribute} #{direction}"
|
13
14
|
|
14
15
|
return relation.reorder(Arel.sql(order)) if
|
15
|
-
|
16
|
+
column_exist?(relation, attribute)
|
16
17
|
|
17
18
|
relation
|
18
19
|
end
|
@@ -32,7 +33,7 @@ module Administrate
|
|
32
33
|
|
33
34
|
private
|
34
35
|
|
35
|
-
attr_reader :attribute
|
36
|
+
attr_reader :attribute, :association_attribute
|
36
37
|
|
37
38
|
def sanitize_direction(direction)
|
38
39
|
%w[asc desc].include?(direction.to_s) ? direction.to_sym : :asc
|
@@ -53,7 +54,7 @@ module Administrate
|
|
53
54
|
def order_by_association(relation)
|
54
55
|
return order_by_count(relation) if has_many_attribute?(relation)
|
55
56
|
|
56
|
-
return
|
57
|
+
return order_by_attribute(relation) if belongs_to_attribute?(relation)
|
57
58
|
|
58
59
|
relation
|
59
60
|
end
|
@@ -68,7 +69,36 @@ module Administrate
|
|
68
69
|
end
|
69
70
|
|
70
71
|
def order_by_id(relation)
|
71
|
-
relation.reorder(
|
72
|
+
relation.reorder(Arel.sql(order_by_id_query(relation)))
|
73
|
+
end
|
74
|
+
|
75
|
+
def order_by_attribute(relation)
|
76
|
+
if ordering_by_association_column?(relation)
|
77
|
+
relation.joins(
|
78
|
+
attribute.to_sym,
|
79
|
+
).reorder(Arel.sql(order_by_attribute_query))
|
80
|
+
else
|
81
|
+
order_by_id(relation)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def ordering_by_association_column?(relation)
|
86
|
+
association_attribute &&
|
87
|
+
column_exist?(
|
88
|
+
reflect_association(relation).klass, association_attribute.to_sym
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
def column_exist?(table, column_name)
|
93
|
+
table.columns_hash.key?(column_name.to_s)
|
94
|
+
end
|
95
|
+
|
96
|
+
def order_by_id_query(relation)
|
97
|
+
"#{relation.table_name}.#{foreign_key(relation)} #{direction}"
|
98
|
+
end
|
99
|
+
|
100
|
+
def order_by_attribute_query
|
101
|
+
"#{attribute.tableize}.#{association_attribute} #{direction}"
|
72
102
|
end
|
73
103
|
|
74
104
|
def has_many_attribute?(relation)
|
@@ -10,8 +10,15 @@ module Administrate
|
|
10
10
|
|
11
11
|
attr_reader :resource
|
12
12
|
|
13
|
-
def attributes
|
14
|
-
|
13
|
+
def attributes(action = nil)
|
14
|
+
action =
|
15
|
+
case action
|
16
|
+
when "update" then "edit"
|
17
|
+
when "create" then "new"
|
18
|
+
else action
|
19
|
+
end
|
20
|
+
|
21
|
+
dashboard.form_attributes(action).map do |attribute|
|
15
22
|
attribute_field(dashboard, resource, attribute, :form)
|
16
23
|
end
|
17
24
|
end
|
data/lib/administrate/search.rb
CHANGED
@@ -4,14 +4,15 @@ require "active_support/core_ext/object/blank"
|
|
4
4
|
module Administrate
|
5
5
|
class Search
|
6
6
|
class Query
|
7
|
-
attr_reader :filters
|
7
|
+
attr_reader :filters, :valid_filters
|
8
8
|
|
9
9
|
def blank?
|
10
10
|
terms.blank? && filters.empty?
|
11
11
|
end
|
12
12
|
|
13
|
-
def initialize(original_query)
|
13
|
+
def initialize(original_query, valid_filters = nil)
|
14
14
|
@original_query = original_query
|
15
|
+
@valid_filters = valid_filters
|
15
16
|
@filters, @terms = parse_query(original_query)
|
16
17
|
end
|
17
18
|
|
@@ -30,7 +31,7 @@ module Administrate
|
|
30
31
|
private
|
31
32
|
|
32
33
|
def filter?(word)
|
33
|
-
word.match?(
|
34
|
+
valid_filters&.any? { |filter| word.match?(/^#{filter}:\w*$/) }
|
34
35
|
end
|
35
36
|
|
36
37
|
def parse_query(query)
|
@@ -38,7 +39,7 @@ module Administrate
|
|
38
39
|
terms = []
|
39
40
|
query.to_s.split.each do |word|
|
40
41
|
if filter?(word)
|
41
|
-
filters << word
|
42
|
+
filters << word
|
42
43
|
else
|
43
44
|
terms << word
|
44
45
|
end
|
@@ -47,10 +48,10 @@ module Administrate
|
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
def initialize(scoped_resource,
|
51
|
-
@
|
51
|
+
def initialize(scoped_resource, dashboard, term)
|
52
|
+
@dashboard = dashboard
|
52
53
|
@scoped_resource = scoped_resource
|
53
|
-
@query = Query.new(term)
|
54
|
+
@query = Query.new(term, valid_filters.keys)
|
54
55
|
end
|
55
56
|
|
56
57
|
def run
|
@@ -65,15 +66,20 @@ module Administrate
|
|
65
66
|
|
66
67
|
private
|
67
68
|
|
68
|
-
def apply_filter(filter, resources)
|
69
|
+
def apply_filter(filter, filter_param, resources)
|
69
70
|
return resources unless filter
|
70
|
-
filter.
|
71
|
+
if filter.parameters.size == 1
|
72
|
+
filter.call(resources)
|
73
|
+
else
|
74
|
+
filter.call(resources, filter_param)
|
75
|
+
end
|
71
76
|
end
|
72
77
|
|
73
78
|
def filter_results(resources)
|
74
|
-
query.filters.each do |
|
79
|
+
query.filters.each do |filter_query|
|
80
|
+
filter_name, filter_param = filter_query.split(":")
|
75
81
|
filter = valid_filters[filter_name]
|
76
|
-
resources = apply_filter(filter, resources)
|
82
|
+
resources = apply_filter(filter, filter_param, resources)
|
77
83
|
end
|
78
84
|
resources
|
79
85
|
end
|
@@ -102,9 +108,7 @@ module Administrate
|
|
102
108
|
end
|
103
109
|
|
104
110
|
def search_attributes
|
105
|
-
|
106
|
-
attribute_types[attribute].searchable?
|
107
|
-
end
|
111
|
+
@dashboard.search_attributes
|
108
112
|
end
|
109
113
|
|
110
114
|
def search_results(resources)
|
@@ -114,15 +118,15 @@ module Administrate
|
|
114
118
|
end
|
115
119
|
|
116
120
|
def valid_filters
|
117
|
-
if @
|
118
|
-
@
|
121
|
+
if @dashboard.class.const_defined?(:COLLECTION_FILTERS)
|
122
|
+
@dashboard.class.const_get(:COLLECTION_FILTERS).stringify_keys
|
119
123
|
else
|
120
124
|
{}
|
121
125
|
end
|
122
126
|
end
|
123
127
|
|
124
128
|
def attribute_types
|
125
|
-
@
|
129
|
+
@dashboard.class.const_get(:ATTRIBUTE_TYPES)
|
126
130
|
end
|
127
131
|
|
128
132
|
def query_table_name(attr)
|
data/lib/administrate/version.rb
CHANGED
@@ -5,7 +5,7 @@ require "administrate/namespace"
|
|
5
5
|
module Administrate
|
6
6
|
class ViewGenerator < Rails::Generators::Base
|
7
7
|
include Administrate::GeneratorHelpers
|
8
|
-
class_option :namespace, type: :string, default:
|
8
|
+
class_option :namespace, type: :string, default: :admin
|
9
9
|
|
10
10
|
def self.template_source_path
|
11
11
|
File.expand_path(
|
data/lib/administrate.rb
CHANGED
@@ -20,4 +20,22 @@ module Administrate
|
|
20
20
|
"if you think otherwise.",
|
21
21
|
)
|
22
22
|
end
|
23
|
+
|
24
|
+
def self.warn_of_deprecated_method(klass, method)
|
25
|
+
ActiveSupport::Deprecation.warn(
|
26
|
+
"The method #{klass}##{method} is deprecated. " +
|
27
|
+
"If you are seeing this message you are probably " +
|
28
|
+
"using a dashboard that depends explicitly on it. " +
|
29
|
+
"Please make sure you update it to a version that " +
|
30
|
+
"does not use a deprecated API",
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.warn_of_deprecated_authorization_method(method)
|
35
|
+
ActiveSupport::Deprecation.warn(
|
36
|
+
"The method `#{method}` is deprecated. " +
|
37
|
+
"Please use `accessible_action?` instead, " +
|
38
|
+
"or see the documentation for other options.",
|
39
|
+
)
|
40
|
+
end
|
23
41
|
end
|
@@ -27,7 +27,7 @@ module Administrate
|
|
27
27
|
COLLECTION_ATTRIBUTE_LIMIT = 4
|
28
28
|
READ_ONLY_ATTRIBUTES = %w[id created_at updated_at]
|
29
29
|
|
30
|
-
class_option :namespace, type: :string, default:
|
30
|
+
class_option :namespace, type: :string, default: :admin
|
31
31
|
|
32
32
|
source_root File.expand_path("../templates", __FILE__)
|
33
33
|
|
@@ -53,9 +53,22 @@ module Administrate
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def attributes
|
56
|
-
|
56
|
+
attrs = (
|
57
|
+
klass.reflections.keys +
|
57
58
|
klass.columns.map(&:name) -
|
58
59
|
redundant_attributes
|
60
|
+
)
|
61
|
+
|
62
|
+
primary_key = attrs.delete(klass.primary_key)
|
63
|
+
created_at = attrs.delete("created_at")
|
64
|
+
updated_at = attrs.delete("updated_at")
|
65
|
+
|
66
|
+
[
|
67
|
+
primary_key,
|
68
|
+
*attrs.sort,
|
69
|
+
created_at,
|
70
|
+
updated_at,
|
71
|
+
].compact
|
59
72
|
end
|
60
73
|
|
61
74
|
def form_attributes
|
@@ -1,5 +1,5 @@
|
|
1
|
-
module <%= namespace.
|
2
|
-
class <%= class_name.pluralize %>Controller < <%= namespace.
|
1
|
+
module <%= namespace.to_s.camelize %>
|
2
|
+
class <%= class_name.pluralize %>Controller < <%= namespace.to_s.camelize %>::ApplicationController
|
3
3
|
# Overwrite any of the RESTful controller actions to implement custom behavior
|
4
4
|
# For example, you may want to send an email after a foo is updated.
|
5
5
|
#
|
@@ -4,7 +4,7 @@
|
|
4
4
|
#
|
5
5
|
# If you want to add pagination or other controller-level concerns,
|
6
6
|
# you're free to overwrite the RESTful controller actions.
|
7
|
-
module <%= namespace.
|
7
|
+
module <%= namespace.camelize %>
|
8
8
|
class ApplicationController < Administrate::ApplicationController
|
9
9
|
before_action :authenticate_admin
|
10
10
|
|