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
@@ -16,4 +16,4 @@ as a count of how many objects are associated through the relationship.
|
|
16
16
|
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/HasMany
|
17
17
|
%>
|
18
18
|
|
19
|
-
<%= pluralize(field.data.size, field.attribute.to_s.humanize.downcase.singularize) %>
|
19
|
+
<%= pluralize(field.data.size, t("activerecord.models.#{field.attribute.to_s.singularize}", default: field.attribute.to_s.humanize.downcase.singularize, count: field.data.size)) %>
|
@@ -18,7 +18,7 @@ The form will be rendered as nested_from to parent relationship.
|
|
18
18
|
|
19
19
|
<%= f.fields_for field.attribute, field.data || field.nested_form.resource.class.new do |has_one_f| %>
|
20
20
|
<fieldset class="field-unit--nested">
|
21
|
-
<legend><%= t "helpers.label.#{f.object_name}.#{field.
|
21
|
+
<legend><%= t "helpers.label.#{f.object_name}.#{field.name}", default: field.name.titleize %></legend>
|
22
22
|
<% field.nested_form.attributes.each do |attribute| -%>
|
23
23
|
<div class="field-unit field-unit--<%= attribute.html_class %>">
|
24
24
|
<%= render_field attribute, f: has_one_f %>
|
@@ -16,7 +16,8 @@ By default, the relationship is rendered as a link to the associated object.
|
|
16
16
|
%>
|
17
17
|
|
18
18
|
<% if field.linkable? %>
|
19
|
-
<%=
|
19
|
+
<%= link_to_if(
|
20
|
+
accessible_action?(field.data, :show),
|
20
21
|
field.display_associated_resource,
|
21
22
|
[namespace, field.data],
|
22
23
|
) %>
|
@@ -18,7 +18,8 @@ All show page attributes of has_one relationship would be rendered
|
|
18
18
|
<% if field.linkable? %>
|
19
19
|
<fieldset class="attribute--nested">
|
20
20
|
<legend>
|
21
|
-
<%=
|
21
|
+
<%= link_to_if(
|
22
|
+
accessible_action?(field.data, :show),
|
22
23
|
field.display_associated_resource,
|
23
24
|
[namespace, field.data],
|
24
25
|
) %>
|
@@ -27,7 +28,7 @@ All show page attributes of has_one relationship would be rendered
|
|
27
28
|
<div>
|
28
29
|
<dt class="attribute-label">
|
29
30
|
<%= t(
|
30
|
-
"helpers.label.#{
|
31
|
+
"helpers.label.#{field.associated_class_name.underscore}.#{attribute.name}",
|
31
32
|
default: attribute.name.titleize,
|
32
33
|
) %>
|
33
34
|
</dt>
|
@@ -17,7 +17,8 @@ By default, the relationship is rendered as a link to the associated object.
|
|
17
17
|
%>
|
18
18
|
|
19
19
|
<% if field.data %>
|
20
|
-
<%=
|
20
|
+
<%= link_to_if(
|
21
|
+
accessible_action?(field.data, :show),
|
21
22
|
field.display_associated_resource,
|
22
23
|
[namespace, field.data]
|
23
24
|
) %>
|
@@ -17,7 +17,7 @@ By default, the relationship is rendered as a link to the associated object.
|
|
17
17
|
%>
|
18
18
|
|
19
19
|
<% if field.data %>
|
20
|
-
<% if
|
20
|
+
<% if accessible_action?(field.data, :show) %>
|
21
21
|
<%= link_to(
|
22
22
|
field.display_associated_resource,
|
23
23
|
[namespace, field.data],
|
@@ -27,7 +27,8 @@ to be displayed on a resource's edit form page.
|
|
27
27
|
:last,
|
28
28
|
:first,
|
29
29
|
field.data,
|
30
|
-
)
|
30
|
+
),
|
31
|
+
include_blank: field.include_blank_option
|
31
32
|
) %>
|
32
33
|
<% else %>
|
33
34
|
<%= f.select(
|
@@ -37,7 +38,8 @@ to be displayed on a resource's edit form page.
|
|
37
38
|
:to_s,
|
38
39
|
:to_s,
|
39
40
|
field.data,
|
40
|
-
)
|
41
|
+
),
|
42
|
+
include_blank: field.include_blank_option
|
41
43
|
) %>
|
42
44
|
<% end %>
|
43
45
|
</div>
|
@@ -2,7 +2,6 @@
|
|
2
2
|
# Time Form Partial
|
3
3
|
|
4
4
|
This partial renders an input element for time attributes.
|
5
|
-
By default, the input is a text field that is augmented with [DateTimePicker].
|
6
5
|
|
7
6
|
## Local variables:
|
8
7
|
|
@@ -12,12 +11,12 @@ By default, the input is a text field that is augmented with [DateTimePicker].
|
|
12
11
|
An instance of [Administrate::Field::Time][1].
|
13
12
|
A wrapper around the tmie attributes pulled from the model.
|
14
13
|
|
15
|
-
[
|
14
|
+
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Time
|
16
15
|
%>
|
17
16
|
|
18
17
|
<div class="field-unit__label">
|
19
18
|
<%= f.label field.attribute %>
|
20
19
|
</div>
|
21
20
|
<div class="field-unit__field">
|
22
|
-
<%= f.
|
21
|
+
<%= f.time_field field.attribute, step: 1 %>
|
23
22
|
</div>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<%#
|
2
2
|
# Url Index Partial
|
3
3
|
|
4
|
-
This partial renders
|
4
|
+
This partial renders a URL address,
|
5
5
|
to be displayed on a resource's index page.
|
6
6
|
|
7
7
|
By default, the value is rendered as an `a` element.
|
@@ -15,6 +15,6 @@ By default, the value is rendered as an `a` element.
|
|
15
15
|
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Url
|
16
16
|
%>
|
17
17
|
|
18
|
-
<%= content_tag :a, href: field.data do %>
|
18
|
+
<%= content_tag :a, href: field.data, **field.html_options do %>
|
19
19
|
<%= field.data %>
|
20
20
|
<% end %>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<%#
|
2
2
|
# Url Show Partial
|
3
3
|
|
4
|
-
This partial renders
|
4
|
+
This partial renders a URL address,
|
5
5
|
to be displayed on a resource's show page.
|
6
6
|
|
7
7
|
By default, the value is rendered as an `a` element.
|
@@ -15,6 +15,6 @@ By default, the value is rendered as an `a` element.
|
|
15
15
|
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Url
|
16
16
|
%>
|
17
17
|
|
18
|
-
<%= content_tag :a, href: field.data do %>
|
18
|
+
<%= content_tag :a, href: field.data, **field.html_options do %>
|
19
19
|
<%= field.data %>
|
20
20
|
<% end %>
|
@@ -21,8 +21,8 @@ de:
|
|
21
21
|
more: "%{count} von %{total_count}"
|
22
22
|
none: Keine
|
23
23
|
form:
|
24
|
-
error:
|
25
|
-
errors: "%{
|
24
|
+
error: Fehler
|
25
|
+
errors: "%{resource_name} konnte nicht gespeichert werden, es gab %{pluralized_errors}."
|
26
26
|
navigation:
|
27
27
|
back_to_app: Zurück zur App
|
28
28
|
search:
|
@@ -0,0 +1,30 @@
|
|
1
|
+
---
|
2
|
+
sl:
|
3
|
+
administrate:
|
4
|
+
actions:
|
5
|
+
confirm: Ali ste preričani?
|
6
|
+
destroy: Izbriši
|
7
|
+
edit: Uredi
|
8
|
+
edit_resource: Uredi %{name}
|
9
|
+
show_resource: Prikaži %{name}
|
10
|
+
new_resource: Dodaj %{name}
|
11
|
+
back: Nazaj
|
12
|
+
controller:
|
13
|
+
create:
|
14
|
+
success: "%{resource} je dodan."
|
15
|
+
destroy:
|
16
|
+
success: "%{resource} je izbrisan."
|
17
|
+
update:
|
18
|
+
success: "%{resource} je posodobljen."
|
19
|
+
fields:
|
20
|
+
has_many:
|
21
|
+
more: Prikazanih %{count} od %{total_count}
|
22
|
+
none: Nobene
|
23
|
+
form:
|
24
|
+
error: napaka
|
25
|
+
errors: "%{resource_name} ni mogoče shraniti zaradi:"
|
26
|
+
navigation:
|
27
|
+
back_to_app: Nazaj v aplikacijo
|
28
|
+
search:
|
29
|
+
clear: Počisti iskanje
|
30
|
+
label: Išči %{resource}
|
@@ -2,8 +2,6 @@
|
|
2
2
|
title: Adding Controllers without a related Model
|
3
3
|
---
|
4
4
|
|
5
|
-
# Adding Controllers without a related Model
|
6
|
-
|
7
5
|
Sometimes you may want to add a custom controller that has no resource
|
8
6
|
related to it (for example for a statistics page).
|
9
7
|
|
@@ -16,9 +14,9 @@ routes are displayed in the sidebar and then add a custom dashboard:
|
|
16
14
|
<div style="padding: 20px">
|
17
15
|
<h1>Stats</h1>
|
18
16
|
<br>
|
19
|
-
<p><b>Total Customers:</b> <%= @stats[:customer_count] %></
|
17
|
+
<p><b>Total Customers:</b> <%= @stats[:customer_count] %></p>
|
20
18
|
<br>
|
21
|
-
<p><b>Total Orders:</b> <%= @stats[:order_count] %></
|
19
|
+
<p><b>Total Orders:</b> <%= @stats[:order_count] %></p>
|
22
20
|
</div>
|
23
21
|
```
|
24
22
|
|
data/docs/authorization.md
CHANGED
@@ -49,23 +49,36 @@ end
|
|
49
49
|
|
50
50
|
## Authorization without Pundit
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
Pundit is not necessary to implement authorization within Administrate. It is
|
53
|
+
simply a common solution that many in the community use, and for this reason
|
54
|
+
Administrate provides a plugin to work with it. However you can use a different
|
55
|
+
solution or roll out your own.
|
56
|
+
|
57
|
+
To integrate a different authorization solution, you will need to
|
58
|
+
implement some methods in `Admin::ApplicationController`
|
59
|
+
or its subclasses.
|
60
|
+
|
61
|
+
These are the methods to override, with examples:
|
55
62
|
|
56
63
|
```ruby
|
57
|
-
#
|
64
|
+
# Used in listings, such as the `index` actions. It
|
65
|
+
# restricts the scope of records that a user can access.
|
66
|
+
# Returns an ActiveRecord scope.
|
58
67
|
def scoped_resource
|
59
68
|
super.where(user: current_user)
|
60
69
|
end
|
61
70
|
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
# Hide links to actions if the user is not allowed to do them
|
68
|
-
def show_action?(action, resource)
|
69
|
-
current_user.can? action, resource
|
71
|
+
# Return true if the current user can access the given
|
72
|
+
# resource, false otherwise.
|
73
|
+
def authorized_action?(resource, action)
|
74
|
+
current_user.can?(resource, action)
|
70
75
|
end
|
71
76
|
```
|
77
|
+
|
78
|
+
Additionally, the method `authorize_resource(resource)`
|
79
|
+
should throw an exception if the current user is not
|
80
|
+
allowed to access the given resource. Normally
|
81
|
+
you wouldn't need to override it, as the default
|
82
|
+
implementation uses `authorized_action?` to produce the
|
83
|
+
correct behaviour. However you may still want to override it
|
84
|
+
if you want to raise a custom error type.
|
@@ -46,17 +46,22 @@ end
|
|
46
46
|
|
47
47
|
## Customizing Actions
|
48
48
|
|
49
|
-
To
|
49
|
+
To disable certain actions globally, you can disable their
|
50
|
+
routes in `config/routes.rb`, using the usual Rails
|
51
|
+
facilities for this. For example:
|
50
52
|
|
51
53
|
```ruby
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
Rails.application.routes.draw do
|
55
|
+
# ...
|
56
|
+
namespace :admin do
|
57
|
+
# ...
|
58
|
+
|
59
|
+
# Payments can only be listed or displayed
|
60
|
+
resources :payments, only: [:index, :show]
|
61
|
+
end
|
55
62
|
end
|
56
63
|
```
|
57
64
|
|
58
|
-
Action is one of `new`, `edit`, `show`, `destroy`.
|
59
|
-
|
60
65
|
## Customizing Default Sorting
|
61
66
|
|
62
67
|
To set the default sorting on the index action you could override `default_sorting_attribute` or `default_sorting_direction` in your dashboard controller like this:
|
@@ -69,4 +74,22 @@ end
|
|
69
74
|
def default_sorting_direction
|
70
75
|
:desc
|
71
76
|
end
|
72
|
-
```
|
77
|
+
```
|
78
|
+
|
79
|
+
## Customizing Redirects after actions
|
80
|
+
|
81
|
+
To set custom redirects after the actions `create`, `update` and `destroy` you can override `after_resource_created_path`, `after_resource_updated_path` or `after_resource_destroyed_path` like this:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
def after_resource_destroyed_path(_requested_resource)
|
85
|
+
{ action: :index, controller: :some_other_resource }
|
86
|
+
end
|
87
|
+
|
88
|
+
def after_resource_created_path(requested_resource)
|
89
|
+
[namespace, requested_resource.some_other_resource]
|
90
|
+
end
|
91
|
+
|
92
|
+
def after_resource_updated_path(requested_resource)
|
93
|
+
[namespace, requested_resource.some_other_resource]
|
94
|
+
end
|
95
|
+
```
|
@@ -8,9 +8,9 @@ edit the dashboard file generated by the installation generator.
|
|
8
8
|
By default, the file will look something like this:
|
9
9
|
|
10
10
|
```ruby
|
11
|
-
require "administrate/
|
11
|
+
require "administrate/base_dashboard"
|
12
12
|
|
13
|
-
class CustomerDashboard < Administrate::
|
13
|
+
class CustomerDashboard < Administrate::BaseDashboard
|
14
14
|
ATTRIBUTE_TYPES = {
|
15
15
|
id: Field::Number,
|
16
16
|
name: Field::String,
|
@@ -65,6 +65,7 @@ specify, including:
|
|
65
65
|
- `Field::Select`
|
66
66
|
- `Field::String`
|
67
67
|
- `Field::Text`
|
68
|
+
- `Field::Url`
|
68
69
|
- `Field::Password`
|
69
70
|
|
70
71
|
## Customizing Fields
|
@@ -76,8 +77,9 @@ which are specified through the `.with_options` class method:
|
|
76
77
|
|
77
78
|
**Field::BelongsTo**
|
78
79
|
|
79
|
-
`:order` - Specifies the order
|
80
|
-
|
80
|
+
`:order` - Specifies the column used to order the records. It will apply both in
|
81
|
+
the table views and in the dropdown menu on the record forms.
|
82
|
+
You can set multiple columns as well with direction. E.g.: `"name, email DESC"`.
|
81
83
|
|
82
84
|
`:scope` - Specifies a custom scope inside a callable. Useful for preloading.
|
83
85
|
Example: `.with_options(scope: -> { MyModel.includes(:rel).limit(5) })`
|
@@ -182,9 +184,9 @@ Or, to display a distance in kilometers, using a space as the delimiter:
|
|
182
184
|
distance: Field::Number.with_options(
|
183
185
|
suffix: " km",
|
184
186
|
decimals: 2,
|
185
|
-
format: {
|
187
|
+
format: {
|
186
188
|
formatter: :number_to_delimited,
|
187
|
-
formatter_options: {
|
189
|
+
formatter_options: {
|
188
190
|
delimiter: ' ',
|
189
191
|
},
|
190
192
|
},
|
@@ -219,9 +221,23 @@ objects to display as.
|
|
219
221
|
`:collection` - Specify the options shown on the select field. It accept either
|
220
222
|
an array or an object responding to `:call`. Defaults to `[]`.
|
221
223
|
|
224
|
+
To customize option labels, pass an array of pairs where the first element is the value submitted with the form and the second element is the label shown to the user.
|
225
|
+
|
226
|
+
For example:
|
227
|
+
|
228
|
+
```ruby
|
229
|
+
currency = Field::Select.with_options(
|
230
|
+
collection: [ ['usd', 'Dollar'], ['eur', 'Euro'], ['yen', 'Yen'] ]
|
231
|
+
)
|
232
|
+
|
233
|
+
```
|
234
|
+
|
222
235
|
`:searchable` - Specify if the attribute should be considered when searching.
|
223
236
|
Default is `true`.
|
224
237
|
|
238
|
+
`:include_blank` - Specifies if the select element to be rendered should include
|
239
|
+
blank option. Default is `false`.
|
240
|
+
|
225
241
|
**Field::String**
|
226
242
|
|
227
243
|
`:searchable` - Specify if the attribute should be considered when searching.
|
@@ -238,6 +254,17 @@ Default is `false`.
|
|
238
254
|
`:truncate` - Set the number of characters to display in the index view.
|
239
255
|
Defaults to `50`.
|
240
256
|
|
257
|
+
**Field::Url**
|
258
|
+
|
259
|
+
`:searchable` - Specify if the attribute should be considered when searching.
|
260
|
+
Default is `true`.
|
261
|
+
|
262
|
+
`:truncate` - Set the number of characters to display in the index view.
|
263
|
+
Defaults to `50`.
|
264
|
+
|
265
|
+
`:html_options` - Specify anchor tag attributes (e.g., `target="_blank"`).
|
266
|
+
Defaults is `{}`.
|
267
|
+
|
241
268
|
**Field::Password**
|
242
269
|
|
243
270
|
`:searchable` - Specify if the attribute should be considered when searching.
|
@@ -317,3 +344,32 @@ COLLECTION_FILTERS = {
|
|
317
344
|
inactive: ->(resources) { resources.inactive }
|
318
345
|
}
|
319
346
|
```
|
347
|
+
|
348
|
+
You can also define a filter with parameters:
|
349
|
+
|
350
|
+
```ruby
|
351
|
+
COLLECTION_FILTERS = {
|
352
|
+
state: ->(resources, attr) { resources.where(state: attr) }
|
353
|
+
}
|
354
|
+
```
|
355
|
+
|
356
|
+
You can now search your resource with 'state:open' and your
|
357
|
+
collection filter Proc will be called with with attr = open.
|
358
|
+
|
359
|
+
## Form Attributes
|
360
|
+
|
361
|
+
You can define different attributes for new/create or edit/update actions:
|
362
|
+
|
363
|
+
```ruby
|
364
|
+
FORM_ATTRIBUTES_NEW = [
|
365
|
+
:name,
|
366
|
+
:email
|
367
|
+
]
|
368
|
+
FORM_ATTRIBUTES_EDIT = [
|
369
|
+
:name,
|
370
|
+
:email,
|
371
|
+
:orders
|
372
|
+
]
|
373
|
+
```
|
374
|
+
|
375
|
+
Or for custom action with constant name `"FORM_ATTRIBUTES_#{action.upcase}"`
|
@@ -5,13 +5,13 @@ title: Extending Administrate
|
|
5
5
|
Apart from the configuration described in these pages, it is possible to
|
6
6
|
extend Administrate's capabilities with the use of plugins. There are a
|
7
7
|
number of plugins available, many of which can be found at [RubyGems.org].
|
8
|
-
|
8
|
+
These are some popular examples:
|
9
9
|
|
10
10
|
1. [ActiveStorage support](https://github.com/Dreamersoul/administrate-field-active_storage)
|
11
|
-
2. [
|
12
|
-
3. [
|
13
|
-
4. [
|
14
|
-
5. [
|
11
|
+
2. [Enum field](https://github.com/Valiot/administrate-field-enum)
|
12
|
+
3. [Nested has-many forms](https://github.com/nickcharlton/administrate-field-nested_has_many)
|
13
|
+
4. [Belongs-to with Ajax search](https://github.com/fishbrain/administrate-field-belongs_to_search)
|
14
|
+
5. [JSONb field plugin for Administrate](https://github.com/codica2/administrate-field-jsonb/)
|
15
15
|
|
16
16
|
See many more at https://rubygems.org/gems/administrate/reverse_dependencies.
|
17
17
|
|
data/docs/getting_started.md
CHANGED
@@ -3,7 +3,7 @@ title: Getting Started
|
|
3
3
|
---
|
4
4
|
|
5
5
|
Administrate is released as a Ruby gem, and can be installed on Rails
|
6
|
-
applications version 5.0 or greater. We support Ruby 2.
|
6
|
+
applications version 5.0 or greater. We support Ruby 2.7 and up.
|
7
7
|
|
8
8
|
First, add the following to your Gemfile:
|
9
9
|
|
@@ -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](/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.
|