administrate 0.17.0 → 0.20.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/javascripts/administrate/components/select.js +3 -0
- 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 +9 -0
- data/app/assets/stylesheets/administrate/components/_field-unit.scss +7 -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 +85 -17
- data/app/controllers/concerns/administrate/punditize.rb +44 -20
- data/app/helpers/administrate/application_helper.rb +24 -6
- data/app/views/administrate/application/_collection.html.erb +5 -6
- data/app/views/administrate/application/_collection_header_actions.html.erb +2 -2
- data/app/views/administrate/application/_collection_item_actions.html.erb +4 -4
- data/app/views/administrate/application/_form.html.erb +19 -4
- data/app/views/administrate/application/_index_header.html.erb +2 -2
- 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 +2 -2
- data/app/views/administrate/application/index.html.erb +1 -1
- data/app/views/administrate/application/new.html.erb +1 -1
- data/app/views/administrate/application/show.html.erb +28 -12
- 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_many/_show.html.erb +2 -1
- data/app/views/fields/has_one/_form.html.erb +15 -5
- data/app/views/fields/has_one/_index.html.erb +2 -1
- data/app/views/fields/has_one/_show.html.erb +20 -13
- 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 +5 -18
- data/app/views/fields/time/_form.html.erb +2 -3
- data/app/views/fields/url/_index.html.erb +1 -1
- data/app/views/fields/url/_show.html.erb +1 -1
- data/app/views/layouts/administrate/application.html.erb +1 -1
- data/config/locales/administrate.de.yml +2 -2
- data/config/locales/administrate.ja.yml +5 -5
- data/config/locales/administrate.sl.yml +30 -0
- data/docs/adding_controllers_without_related_model.md +2 -2
- data/docs/authorization.md +43 -20
- data/docs/customizing_controller_actions.md +25 -6
- data/docs/customizing_dashboards.md +88 -10
- 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 +39 -3
- data/lib/administrate/engine.rb +2 -2
- data/lib/administrate/field/associative.rb +18 -8
- data/lib/administrate/field/base.rb +4 -0
- data/lib/administrate/field/belongs_to.rb +9 -2
- data/lib/administrate/field/deferred.rb +5 -1
- data/lib/administrate/field/has_many.rb +20 -6
- data/lib/administrate/field/has_one.rb +4 -0
- data/lib/administrate/field/number.rb +2 -8
- data/lib/administrate/field/polymorphic.rb +2 -1
- data/lib/administrate/field/select.rb +19 -9
- data/lib/administrate/field/url.rb +4 -0
- data/lib/administrate/not_authorized_error.rb +20 -0
- data/lib/administrate/order.rb +73 -17
- data/lib/administrate/page/base.rb +4 -0
- data/lib/administrate/page/collection.rb +1 -0
- data/lib/administrate/page/form.rb +9 -8
- data/lib/administrate/page/show.rb +10 -2
- data/lib/administrate/resource_resolver.rb +2 -1
- data/lib/administrate/search.rb +1 -1
- data/lib/administrate/version.rb +1 -1
- data/lib/administrate/view_generator.rb +6 -1
- data/lib/administrate.rb +24 -2
- data/lib/generators/administrate/dashboard/dashboard_generator.rb +20 -2
- data/lib/generators/administrate/dashboard/templates/controller.rb.erb +2 -2
- data/lib/generators/administrate/install/install_generator.rb +6 -1
- data/lib/generators/administrate/routes/routes_generator.rb +11 -2
- data/lib/generators/administrate/test_record.rb +21 -0
- metadata +39 -46
- 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,149 @@
|
|
1
|
+
---
|
2
|
+
title: Customising the search
|
3
|
+
---
|
4
|
+
|
5
|
+
Administrate dashboards provide a search function, but it is quite basic.
|
6
|
+
Things like search across complex associations, inside JSON columns, or outside
|
7
|
+
the database (eg: an Elasticsearch index) are not possible out of the box.
|
8
|
+
|
9
|
+
Fortunately, Administrate is just Rails, so you can use your existing Rails
|
10
|
+
knowledge to customize the search feature. Let's look into that.
|
11
|
+
|
12
|
+
## In short
|
13
|
+
|
14
|
+
Override the `filter_resources` method in your admin controllers in order
|
15
|
+
to customize the search.
|
16
|
+
|
17
|
+
It has two parameters:
|
18
|
+
|
19
|
+
* `resources`: an ActiveRecord relation for the model on whose dashboard the
|
20
|
+
search originated.
|
21
|
+
* `search_term:`: a string representing the search query entered by the user.
|
22
|
+
|
23
|
+
Return an ActiveRecord relation for the same model as `resources`, matching
|
24
|
+
the desired search results.
|
25
|
+
|
26
|
+
## In more detail
|
27
|
+
|
28
|
+
When you install Administrate in your application, it generates an admin
|
29
|
+
controller for each of your ActiveRecord models, as well as a base controller
|
30
|
+
that all of these inherit from.
|
31
|
+
|
32
|
+
For example, if you have two ActiveRecord models: `Person` and `Address`,
|
33
|
+
running `rails generate administrate:install` will get you the following
|
34
|
+
files (plus others that are not relevant here):
|
35
|
+
|
36
|
+
* `app/controllers/admin/people_controller.rb`
|
37
|
+
* `app/controllers/admin/addresses_controller.rb`
|
38
|
+
* `app/controllers/admin/application_controller.rb`
|
39
|
+
|
40
|
+
By default, searches are handled by the `index` action of the controller that
|
41
|
+
the user was visiting when they performed the search. For example, if a user
|
42
|
+
is visiting the People dashboard and submits a search, the user is sent to
|
43
|
+
the path `/admin/people?search=<search query>`. This is routed to
|
44
|
+
`Admin::PeopleController#index`, where the search query can be read as
|
45
|
+
`params[:search]`.
|
46
|
+
|
47
|
+
By default, these controllers are empty. Administrate's code is implemented
|
48
|
+
at `Administrate::ApplicationController`, from which all inherit. This is
|
49
|
+
where search is implemented. You can read the code yourself at:
|
50
|
+
https://github.com/thoughtbot/administrate/blob/main/app/controllers/administrate/application_controller.rb.
|
51
|
+
|
52
|
+
It is in the linked code that you can see what Administrate actually does.
|
53
|
+
For example, this is the `index` action at the time of writing these lines:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
def index
|
57
|
+
authorize_resource(resource_class)
|
58
|
+
search_term = params[:search].to_s.strip
|
59
|
+
resources = filter_resources(scoped_resource, search_term: search_term)
|
60
|
+
resources = apply_collection_includes(resources)
|
61
|
+
resources = order.apply(resources)
|
62
|
+
resources = resources.page(params[:_page]).per(records_per_page)
|
63
|
+
page = Administrate::Page::Collection.new(dashboard, order: order)
|
64
|
+
|
65
|
+
render locals: {
|
66
|
+
resources: resources,
|
67
|
+
search_term: search_term,
|
68
|
+
page: page,
|
69
|
+
show_search_bar: show_search_bar?,
|
70
|
+
}
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
What the above does is applying a few transforms
|
75
|
+
to the variable `resources`, filtering it, applying includes for associations,
|
76
|
+
ordering the results, paginating them, and finally handing them over to the
|
77
|
+
template in order to be rendered. All this is pretty standard Rails, although
|
78
|
+
split into individual steps that can be overriden by developers in order
|
79
|
+
to add customizations, and ultimately wrapped in an instance of
|
80
|
+
`Administrate::Page::Collection` which will read your dashboard definitions
|
81
|
+
and figure out what fields you want displayed.
|
82
|
+
|
83
|
+
It is the filtering part where the search is implemented. You will notice the
|
84
|
+
`filter_resources` method, which takes a parameter `search_term`. This is what
|
85
|
+
this method looks like at the moment:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
def filter_resources(resources, search_term:)
|
89
|
+
Administrate::Search.new(
|
90
|
+
resources,
|
91
|
+
dashboard,
|
92
|
+
search_term,
|
93
|
+
).run
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
The class `Administrate::Search` implements the default search facilities
|
98
|
+
within Administrate... but you do not have to worry about it! You can ignore
|
99
|
+
it and implement your own search in `filter_resources`. For example, you
|
100
|
+
could write your own version in your controller, to override Administrate's
|
101
|
+
own. Something like this:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
def filter_resources(resources, search_term:)
|
105
|
+
resources.where(first_name: search_term)
|
106
|
+
.or(People.where(last_name: search_term))
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
It can be as complex (or simple) as you want, as long as the return value
|
111
|
+
of the method is an ActiveRecord relation.
|
112
|
+
|
113
|
+
What if you do not want to search in the DB? For example, say that your records
|
114
|
+
are indexed by Elasticsearch or something like that. You can still search
|
115
|
+
in your external index and convert the results to an ActiveRecord relation.
|
116
|
+
Here's an example:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
def filter_resources(resources, search_term:)
|
120
|
+
# Run the search term through your search facility
|
121
|
+
results = MySuperDuperSearchSystem.search_people(search_term)
|
122
|
+
|
123
|
+
# Collect the ids of the results. This assumes that they will
|
124
|
+
# be the same ones as in the DB.
|
125
|
+
record_ids = results.entries.map(&:id)
|
126
|
+
|
127
|
+
# Use the ids to create an ActiveRecord relation and return it
|
128
|
+
People.where(id: record_ids)
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
Note though: the records must still exist in the DB. Administrate does
|
133
|
+
require ActiveRecord in order to show tables, and to display, create and edit
|
134
|
+
records.
|
135
|
+
|
136
|
+
## A working example
|
137
|
+
|
138
|
+
The [Administrate demo app](https://administrate-demo.herokuapp.com/admin)
|
139
|
+
includes an example of custom search in the "Log Entries" dashboard.
|
140
|
+
In this app, each `LogEntry` instance has a polymorphic `belongs_to`
|
141
|
+
association to a `:logeable`. Logeables are other models for which logs can be
|
142
|
+
created. At the moment these are `Order` and `Customer`.
|
143
|
+
|
144
|
+
Administrate's default search is not able to search across polymorphic
|
145
|
+
associations, and therefore it is not possible to search logs by the contents
|
146
|
+
of their logeables. Fortunately this can be fixed with a custom search. This is
|
147
|
+
done by implementing `Admin::LogEntriesController#filter_resources` to override
|
148
|
+
the default search. You can see the code at
|
149
|
+
https://github.com/thoughtbot/administrate/blob/main/spec/example_app/app/controllers/admin/log_entries_controller.rb
|
@@ -2,7 +2,8 @@
|
|
2
2
|
title: Hiding Dashboards from the Sidebar
|
3
3
|
---
|
4
4
|
|
5
|
-
Resources can be removed
|
5
|
+
Resources can be removed from the sidebar by removing their `index` action
|
6
|
+
from the routes. For example:
|
6
7
|
|
7
8
|
```ruby
|
8
9
|
# config/routes.rb
|
@@ -16,4 +17,5 @@ Rails.application.routes.draw do
|
|
16
17
|
end
|
17
18
|
```
|
18
19
|
|
19
|
-
In this case, only Orders and Products will appear in the sidebar, while
|
20
|
+
In this case, only Orders and Products will appear in the sidebar, while
|
21
|
+
Line Items can still appear as an association.
|
@@ -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)
|
@@ -51,6 +51,12 @@ module Administrate
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def form_attributes(action = nil)
|
54
|
+
action =
|
55
|
+
case action
|
56
|
+
when "update" then "edit"
|
57
|
+
when "create" then "new"
|
58
|
+
else action
|
59
|
+
end
|
54
60
|
specific_form_attributes_for(action) || self.class::FORM_ATTRIBUTES
|
55
61
|
end
|
56
62
|
|
@@ -62,11 +68,18 @@ module Administrate
|
|
62
68
|
self.class.const_get(cname) if self.class.const_defined?(cname)
|
63
69
|
end
|
64
70
|
|
65
|
-
def permitted_attributes
|
66
|
-
form_attributes
|
71
|
+
def permitted_attributes(action = nil)
|
72
|
+
attributes = form_attributes action
|
73
|
+
|
74
|
+
if attributes.is_a? Hash
|
75
|
+
attributes = attributes.values.flatten
|
76
|
+
end
|
77
|
+
|
78
|
+
attributes.map do |attr|
|
67
79
|
attribute_types[attr].permitted_attribute(
|
68
80
|
attr,
|
69
81
|
resource_class: self.class.model,
|
82
|
+
action: action,
|
70
83
|
)
|
71
84
|
end.uniq
|
72
85
|
end
|
@@ -76,7 +89,11 @@ module Administrate
|
|
76
89
|
end
|
77
90
|
|
78
91
|
def collection_attributes
|
79
|
-
self.class::COLLECTION_ATTRIBUTES
|
92
|
+
if self.class::COLLECTION_ATTRIBUTES.is_a?(Hash)
|
93
|
+
self.class::COLLECTION_ATTRIBUTES.values.flatten
|
94
|
+
else
|
95
|
+
self.class::COLLECTION_ATTRIBUTES
|
96
|
+
end
|
80
97
|
end
|
81
98
|
|
82
99
|
def search_attributes
|
@@ -94,9 +111,20 @@ module Administrate
|
|
94
111
|
end
|
95
112
|
|
96
113
|
def item_includes
|
114
|
+
# Deprecated, internal usage has moved to #item_associations
|
115
|
+
Administrate.warn_of_deprecated_method(self.class, :item_includes)
|
97
116
|
attribute_includes(show_page_attributes)
|
98
117
|
end
|
99
118
|
|
119
|
+
def item_associations
|
120
|
+
attributes = if show_page_attributes.is_a?(Hash)
|
121
|
+
show_page_attributes.values.flatten
|
122
|
+
else
|
123
|
+
show_page_attributes
|
124
|
+
end
|
125
|
+
attribute_associated attributes
|
126
|
+
end
|
127
|
+
|
100
128
|
private
|
101
129
|
|
102
130
|
def attribute_not_found_message(attr)
|
@@ -104,6 +132,14 @@ module Administrate
|
|
104
132
|
end
|
105
133
|
|
106
134
|
def attribute_includes(attributes)
|
135
|
+
attributes.map do |key|
|
136
|
+
field = attribute_type_for(key)
|
137
|
+
|
138
|
+
key if field.eager_load?
|
139
|
+
end.compact
|
140
|
+
end
|
141
|
+
|
142
|
+
def attribute_associated(attributes)
|
107
143
|
attributes.map do |key|
|
108
144
|
field = attribute_type_for(key)
|
109
145
|
|
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"
|
@@ -7,12 +7,16 @@ module Administrate
|
|
7
7
|
reflection(resource_class, attr).foreign_key
|
8
8
|
end
|
9
9
|
|
10
|
+
def self.association_primary_key_for(resource_class, attr)
|
11
|
+
reflection(resource_class, attr).association_primary_key
|
12
|
+
end
|
13
|
+
|
10
14
|
def self.associated_class(resource_class, attr)
|
11
15
|
reflection(resource_class, attr).klass
|
12
16
|
end
|
13
17
|
|
14
18
|
def self.associated_class_name(resource_class, attr)
|
15
|
-
|
19
|
+
associated_class(resource_class, attr).name
|
16
20
|
end
|
17
21
|
|
18
22
|
def self.reflection(resource_class, attr)
|
@@ -31,12 +35,6 @@ module Administrate
|
|
31
35
|
end
|
32
36
|
end
|
33
37
|
|
34
|
-
private
|
35
|
-
|
36
|
-
def associated_dashboard
|
37
|
-
"#{associated_class_name}Dashboard".constantize.new
|
38
|
-
end
|
39
|
-
|
40
38
|
def associated_class_name
|
41
39
|
if option_given?(:class_name)
|
42
40
|
deprecated_option(:class_name)
|
@@ -48,11 +46,23 @@ module Administrate
|
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
49
|
+
private
|
50
|
+
|
51
|
+
def associated_dashboard
|
52
|
+
"#{associated_class_name}Dashboard".constantize.new
|
53
|
+
end
|
54
|
+
|
51
55
|
def primary_key
|
56
|
+
# Deprecated, renamed `association_primary_key`
|
57
|
+
Administrate.warn_of_deprecated_method(self.class, :primary_key)
|
58
|
+
association_primary_key
|
59
|
+
end
|
60
|
+
|
61
|
+
def association_primary_key
|
52
62
|
if option_given?(:primary_key)
|
53
63
|
deprecated_option(:primary_key)
|
54
64
|
else
|
55
|
-
|
65
|
+
self.class.association_primary_key_for(resource.class, attribute)
|
56
66
|
end
|
57
67
|
end
|
58
68
|
|
@@ -13,18 +13,25 @@ module Administrate
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
def self.eager_load?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
16
20
|
def permitted_attribute
|
17
21
|
foreign_key
|
18
22
|
end
|
19
23
|
|
20
24
|
def associated_resource_options
|
21
25
|
candidate_resources.map do |resource|
|
22
|
-
[
|
26
|
+
[
|
27
|
+
display_candidate_resource(resource),
|
28
|
+
resource.send(association_primary_key),
|
29
|
+
]
|
23
30
|
end
|
24
31
|
end
|
25
32
|
|
26
33
|
def selected_option
|
27
|
-
data
|
34
|
+
data&.send(association_primary_key)
|
28
35
|
end
|
29
36
|
|
30
37
|
def include_blank_option
|
@@ -25,12 +25,16 @@ module Administrate
|
|
25
25
|
deferred_class.associative?
|
26
26
|
end
|
27
27
|
|
28
|
+
def eager_load?
|
29
|
+
deferred_class.eager_load?
|
30
|
+
end
|
31
|
+
|
28
32
|
def searchable?
|
29
33
|
options.fetch(:searchable, deferred_class.searchable?)
|
30
34
|
end
|
31
35
|
|
32
36
|
def searchable_field
|
33
|
-
|
37
|
+
Administrate.deprecator.warn(
|
34
38
|
"searchable_field is deprecated, use searchable_fields instead",
|
35
39
|
)
|
36
40
|
options.fetch(:searchable_field)
|
@@ -22,7 +22,11 @@ module Administrate
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def associated_collection(order = self.order)
|
25
|
-
Administrate::Page::Collection.new(
|
25
|
+
Administrate::Page::Collection.new(
|
26
|
+
associated_dashboard,
|
27
|
+
order: order,
|
28
|
+
collection_attributes: options[:collection_attributes],
|
29
|
+
)
|
26
30
|
end
|
27
31
|
|
28
32
|
def attribute_key
|
@@ -30,21 +34,28 @@ module Administrate
|
|
30
34
|
end
|
31
35
|
|
32
36
|
def associated_resource_options
|
33
|
-
candidate_resources.map do |
|
34
|
-
[
|
37
|
+
candidate_resources.map do |associated_resource|
|
38
|
+
[
|
39
|
+
display_candidate_resource(associated_resource),
|
40
|
+
associated_resource.send(association_primary_key),
|
41
|
+
]
|
35
42
|
end
|
36
43
|
end
|
37
44
|
|
38
45
|
def selected_options
|
39
46
|
return if data.empty?
|
40
47
|
|
41
|
-
data.map { |object| object.send(
|
48
|
+
data.map { |object| object.send(association_primary_key) }
|
42
49
|
end
|
43
50
|
|
44
51
|
def limit
|
45
52
|
options.fetch(:limit, DEFAULT_LIMIT)
|
46
53
|
end
|
47
54
|
|
55
|
+
def paginate?
|
56
|
+
limit.respond_to?(:positive?) ? limit.positive? : limit.present?
|
57
|
+
end
|
58
|
+
|
48
59
|
def permitted_attribute
|
49
60
|
self.class.permitted_attribute(
|
50
61
|
attribute,
|
@@ -53,12 +64,15 @@ module Administrate
|
|
53
64
|
end
|
54
65
|
|
55
66
|
def resources(page = 1, order = self.order)
|
56
|
-
resources = order.apply(data)
|
67
|
+
resources = order.apply(data)
|
68
|
+
if paginate?
|
69
|
+
resources = resources.page(page).per(limit)
|
70
|
+
end
|
57
71
|
includes.any? ? resources.includes(*includes) : resources
|
58
72
|
end
|
59
73
|
|
60
74
|
def more_than_limit?
|
61
|
-
data.count(:all) > limit
|
75
|
+
paginate? && data.count(:all) > limit
|
62
76
|
end
|
63
77
|
|
64
78
|
def data
|
@@ -38,14 +38,8 @@ module Administrate
|
|
38
38
|
formatter = options[:format][:formatter]
|
39
39
|
formatter_options = options[:format][:formatter_options].to_h
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
ActiveSupport::NumberHelper.number_to_delimited(
|
44
|
-
result, **formatter_options
|
45
|
-
)
|
46
|
-
else
|
47
|
-
result
|
48
|
-
end
|
41
|
+
ActiveSupport::NumberHelper.
|
42
|
+
try(formatter, result, **formatter_options) || result
|
49
43
|
end
|
50
44
|
end
|
51
45
|
end
|
@@ -8,22 +8,32 @@ module Administrate
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def selectable_options
|
11
|
-
|
11
|
+
values =
|
12
|
+
if options.key?(:collection)
|
13
|
+
options.fetch(:collection)
|
14
|
+
elsif active_record_enum?
|
15
|
+
active_record_enum_values
|
16
|
+
else
|
17
|
+
[]
|
18
|
+
end
|
19
|
+
|
20
|
+
if values.respond_to? :call
|
21
|
+
values = values.arity.positive? ? values.call(self) : values.call
|
22
|
+
end
|
23
|
+
|
24
|
+
values
|
12
25
|
end
|
13
26
|
|
14
27
|
def include_blank_option
|
15
28
|
options.fetch(:include_blank, false)
|
16
29
|
end
|
17
30
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
values = options.fetch(:collection, [])
|
22
|
-
if values.respond_to? :call
|
23
|
-
return values.arity.positive? ? values.call(self) : values.call
|
24
|
-
end
|
31
|
+
def active_record_enum?
|
32
|
+
resource.class.defined_enums.key?(attribute.to_s)
|
33
|
+
end
|
25
34
|
|
26
|
-
|
35
|
+
def active_record_enum_values
|
36
|
+
resource.class.defined_enums[attribute.to_s].map(&:first)
|
27
37
|
end
|
28
38
|
end
|
29
39
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Administrate
|
2
|
+
class NotAuthorizedError < StandardError
|
3
|
+
def initialize(action:, resource:)
|
4
|
+
@action = action
|
5
|
+
@resource = resource
|
6
|
+
|
7
|
+
case resource
|
8
|
+
when String, Symbol
|
9
|
+
super("Not allowed to perform #{action.inspect} on #{resource.inspect}")
|
10
|
+
when Module
|
11
|
+
super("Not allowed to perform #{action.inspect} on #{resource.name}")
|
12
|
+
else
|
13
|
+
super(
|
14
|
+
"Not allowed to perform #{action.inspect} on the given " +
|
15
|
+
resource.class.name
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|