administrate 0.18.0 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/administrate/components/select.js +3 -0
- data/app/controllers/administrate/application_controller.rb +6 -4
- data/app/controllers/concerns/administrate/punditize.rb +38 -12
- data/app/views/administrate/application/_collection.html.erb +2 -3
- data/app/views/administrate/application/_index_header.html.erb +1 -1
- data/app/views/administrate/application/_navigation.html.erb +1 -1
- data/app/views/administrate/application/_pagination.html.erb +1 -1
- data/app/views/administrate/application/edit.html.erb +1 -1
- data/app/views/administrate/application/new.html.erb +1 -1
- data/app/views/administrate/application/show.html.erb +1 -1
- data/app/views/fields/has_many/_show.html.erb +2 -1
- data/app/views/fields/select/_form.html.erb +5 -18
- data/app/views/layouts/administrate/application.html.erb +1 -1
- data/config/locales/administrate.ja.yml +5 -5
- data/docs/authorization.md +18 -8
- data/docs/customizing_dashboards.md +22 -12
- data/docs/getting_started.md +1 -1
- data/docs/guides/customising_search.md +1 -1
- data/lib/administrate/base_dashboard.rb +9 -2
- data/lib/administrate/field/associative.rb +11 -1
- data/lib/administrate/field/belongs_to.rb +5 -2
- data/lib/administrate/field/has_many.rb +15 -5
- data/lib/administrate/field/polymorphic.rb +2 -1
- data/lib/administrate/field/select.rb +19 -9
- data/lib/administrate/not_authorized_error.rb +3 -1
- data/lib/administrate/order.rb +43 -18
- data/lib/administrate/page/form.rb +0 -7
- 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/generators/administrate/dashboard/dashboard_generator.rb +6 -1
- 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 +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a94bb51af4fa730f84d042f402122cc3073894e67494309dab4621b5f39b36fa
|
4
|
+
data.tar.gz: 57e7d78f316c635be65735e5c4220bd4e8d777c29c1d92741ab2520998080cde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d7b0a4b21404d16b48a5545e57202b73b3d782e23a5b26b5ed9e52ab3a66069717e23b1e099727eba9ff99315ba757d8ad0b739895a56775fbb5f3f8279df29
|
7
|
+
data.tar.gz: 07cc800c0c7cca79231ac047d10120ef63ec1c7d95aa5dccac9c7b1b5a99cafaccc2c31165c7350920721e622063190b0f804fb05d1e436c518511639802d4bd
|
@@ -40,7 +40,7 @@ module Administrate
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def create
|
43
|
-
resource =
|
43
|
+
resource = new_resource(resource_params)
|
44
44
|
authorize_resource(resource)
|
45
45
|
|
46
46
|
if resource.save
|
@@ -201,7 +201,7 @@ module Administrate
|
|
201
201
|
|
202
202
|
def resource_params
|
203
203
|
params.require(resource_class.model_name.param_key).
|
204
|
-
permit(dashboard.permitted_attributes).
|
204
|
+
permit(dashboard.permitted_attributes(action_name)).
|
205
205
|
transform_values { |v| read_param_value(v) }
|
206
206
|
end
|
207
207
|
|
@@ -214,6 +214,8 @@ module Administrate
|
|
214
214
|
end
|
215
215
|
elsif data.is_a?(ActionController::Parameters)
|
216
216
|
data.transform_values { |v| read_param_value(v) }
|
217
|
+
elsif data.is_a?(String) && data.blank?
|
218
|
+
nil
|
217
219
|
else
|
218
220
|
data
|
219
221
|
end
|
@@ -265,8 +267,8 @@ module Administrate
|
|
265
267
|
end
|
266
268
|
helper_method :show_action?
|
267
269
|
|
268
|
-
def new_resource
|
269
|
-
resource_class.new
|
270
|
+
def new_resource(params = {})
|
271
|
+
resource_class.new(params)
|
270
272
|
end
|
271
273
|
helper_method :new_resource
|
272
274
|
|
@@ -2,37 +2,63 @@ module Administrate
|
|
2
2
|
module Punditize
|
3
3
|
if Object.const_defined?("Pundit")
|
4
4
|
extend ActiveSupport::Concern
|
5
|
-
|
5
|
+
|
6
|
+
if Pundit.const_defined?(:Authorization)
|
7
|
+
include Pundit::Authorization
|
8
|
+
else
|
9
|
+
include Pundit
|
10
|
+
end
|
6
11
|
|
7
12
|
included do
|
8
13
|
private
|
9
14
|
|
15
|
+
def policy_namespace
|
16
|
+
[]
|
17
|
+
end
|
18
|
+
|
10
19
|
def scoped_resource
|
11
|
-
|
20
|
+
namespaced_scope = policy_namespace + [super]
|
21
|
+
policy_scope!(pundit_user, namespaced_scope)
|
12
22
|
end
|
13
23
|
|
14
24
|
def authorize_resource(resource)
|
15
|
-
|
25
|
+
namespaced_resource = policy_namespace + [resource]
|
26
|
+
authorize namespaced_resource
|
16
27
|
end
|
17
28
|
|
18
29
|
def authorized_action?(resource, action)
|
19
|
-
|
30
|
+
namespaced_resource = policy_namespace + [resource]
|
31
|
+
policy = Pundit.policy!(pundit_user, namespaced_resource)
|
32
|
+
policy.send("#{action}?".to_sym)
|
20
33
|
end
|
21
34
|
end
|
22
35
|
|
23
36
|
private
|
24
37
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
38
|
+
def policy_scope!(user, scope)
|
39
|
+
policy_scope_class = Pundit::PolicyFinder.new(scope).scope!
|
40
|
+
|
41
|
+
begin
|
42
|
+
policy_scope = policy_scope_class.new(user, pundit_model(scope))
|
43
|
+
rescue ArgumentError
|
44
|
+
raise(Pundit::InvalidConstructorError,
|
45
|
+
"Invalid #<#{policy_scope_class}> constructor is called")
|
46
|
+
end
|
47
|
+
|
48
|
+
if policy_scope.respond_to? :resolve_admin
|
49
|
+
ActiveSupport::Deprecation.warn(
|
50
|
+
"Pundit policy scope `resolve_admin` method is deprecated. " +
|
51
|
+
"Please use a namespaced pundit policy instead.",
|
52
|
+
)
|
53
|
+
policy_scope.resolve_admin
|
32
54
|
else
|
33
|
-
|
55
|
+
policy_scope.resolve
|
34
56
|
end
|
35
57
|
end
|
58
|
+
|
59
|
+
def pundit_model(record)
|
60
|
+
record.is_a?(Array) ? record.last : record
|
61
|
+
end
|
36
62
|
end
|
37
63
|
end
|
38
64
|
end
|
@@ -27,15 +27,14 @@ to display a collection of resources in an HTML table.
|
|
27
27
|
cell-label--<%= collection_presenter.ordered_html_class(attr_name) %>
|
28
28
|
cell-label--<%= "#{collection_presenter.resource_name}_#{attr_name}" %>"
|
29
29
|
scope="col"
|
30
|
-
role="columnheader"
|
31
30
|
aria-sort="<%= sort_order(collection_presenter.ordered_html_class(attr_name)) %>">
|
32
31
|
<%= link_to(sanitized_order_params(page, collection_field_name).merge(
|
33
32
|
collection_presenter.order_params_for(attr_name, key: collection_field_name)
|
34
33
|
)) do %>
|
35
34
|
<%= t(
|
36
35
|
"helpers.label.#{collection_presenter.resource_name}.#{attr_name}",
|
37
|
-
default: resource_class.human_attribute_name(attr_name),
|
38
|
-
)
|
36
|
+
default: resource_class.human_attribute_name(attr_name).titleize,
|
37
|
+
) %>
|
39
38
|
<% if collection_presenter.ordered_by?(attr_name) %>
|
40
39
|
<span class="cell-label__sort-indicator cell-label__sort-indicator--<%= collection_presenter.ordered_html_class(attr_name) %>">
|
41
40
|
<svg aria-hidden="true">
|
@@ -7,7 +7,7 @@ for all resources in the admin dashboard,
|
|
7
7
|
as defined by the routes in the `admin/` namespace
|
8
8
|
%>
|
9
9
|
|
10
|
-
<nav class="navigation"
|
10
|
+
<nav class="navigation">
|
11
11
|
<%= link_to(t("administrate.navigation.back_to_app"), root_url, class: "button button--alt button--nav") if defined?(root_url) %>
|
12
12
|
|
13
13
|
<% Administrate::Namespace.new(namespace).resources_with_index_route.each do |resource| %>
|
@@ -1 +1 @@
|
|
1
|
-
<%= paginate resources, param_name:
|
1
|
+
<%= paginate resources, param_name: local_assigns.fetch(:param_name, "_page") %>
|
@@ -17,7 +17,7 @@ It displays a header, and renders the `_form` partial to do the heavy lifting.
|
|
17
17
|
|
18
18
|
<% content_for(:title) { t("administrate.actions.edit_resource", name: page.page_title) } %>
|
19
19
|
|
20
|
-
<header class="main-content__header"
|
20
|
+
<header class="main-content__header">
|
21
21
|
<h1 class="main-content__page-title">
|
22
22
|
<%= content_for(:title) %>
|
23
23
|
</h1>
|
@@ -18,7 +18,7 @@ as well as a link to its edit page.
|
|
18
18
|
|
19
19
|
<% content_for(:title) { t("administrate.actions.show_resource", name: page.page_title) } %>
|
20
20
|
|
21
|
-
<header class="main-content__header"
|
21
|
+
<header class="main-content__header">
|
22
22
|
<h1 class="main-content__page-title">
|
23
23
|
<%= content_for(:title) %>
|
24
24
|
</h1>
|
@@ -28,9 +28,10 @@ from the associated resource class's dashboard.
|
|
28
28
|
page: page,
|
29
29
|
resources: field.resources(page_number, order),
|
30
30
|
table_title: field.name,
|
31
|
+
resource_class: field.associated_class,
|
31
32
|
) %>
|
32
33
|
<% if field.more_than_limit? %>
|
33
|
-
<%=
|
34
|
+
<%= render("pagination", resources: field.resources(page_number), param_name: "#{field.name}[page]") %>
|
34
35
|
<% end %>
|
35
36
|
|
36
37
|
<% else %>
|
@@ -19,27 +19,14 @@ to be displayed on a resource's edit form page.
|
|
19
19
|
<%= f.label field.attribute %>
|
20
20
|
</div>
|
21
21
|
<div class="field-unit__field">
|
22
|
-
|
23
|
-
|
22
|
+
<%=
|
23
|
+
f.select(
|
24
24
|
field.attribute,
|
25
|
-
|
25
|
+
options_for_select(
|
26
26
|
field.selectable_options,
|
27
|
-
:last,
|
28
|
-
:first,
|
29
27
|
field.data,
|
30
28
|
),
|
31
29
|
include_blank: field.include_blank_option
|
32
|
-
)
|
33
|
-
|
34
|
-
<%= f.select(
|
35
|
-
field.attribute,
|
36
|
-
options_from_collection_for_select(
|
37
|
-
field.selectable_options,
|
38
|
-
:to_s,
|
39
|
-
:to_s,
|
40
|
-
field.data,
|
41
|
-
),
|
42
|
-
include_blank: field.include_blank_option
|
43
|
-
) %>
|
44
|
-
<% end %>
|
30
|
+
)
|
31
|
+
%>
|
45
32
|
</div>
|
@@ -5,9 +5,9 @@ ja:
|
|
5
5
|
confirm: 本当によろしいですか?
|
6
6
|
destroy: 削除
|
7
7
|
edit: 編集
|
8
|
-
edit_resource:
|
9
|
-
show_resource:
|
10
|
-
new_resource:
|
8
|
+
edit_resource: "%{name}を編集"
|
9
|
+
show_resource: "%{name}を参照"
|
10
|
+
new_resource: "%{name}を作成"
|
11
11
|
back: 戻る
|
12
12
|
controller:
|
13
13
|
create:
|
@@ -22,9 +22,9 @@ ja:
|
|
22
22
|
none: データがありません
|
23
23
|
form:
|
24
24
|
error: エラー
|
25
|
-
errors: "%{pluralized_errors}のため%{resource_name}
|
25
|
+
errors: "%{pluralized_errors}のため%{resource_name}を保存できませんでした。"
|
26
26
|
navigation:
|
27
27
|
back_to_app: アプリに戻る
|
28
28
|
search:
|
29
29
|
clear: 検索をクリアする
|
30
|
-
label:
|
30
|
+
label: "%{resource}を検索"
|
data/docs/authorization.md
CHANGED
@@ -28,20 +28,30 @@ technically have access to see in the main app. For example, a user may
|
|
28
28
|
have all public records in their scope, but you want to only show *their*
|
29
29
|
records in the admin interface to reduce confusion.
|
30
30
|
|
31
|
-
In this case, you can add
|
32
|
-
|
31
|
+
In this case, you can add additional pundit `policy_namespace` in your controller
|
32
|
+
and Administrate will use the namespaced pundit policy instead.
|
33
33
|
|
34
34
|
For example:
|
35
35
|
|
36
36
|
```ruby
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
# app/controllers/admin/posts_controller.rb
|
38
|
+
module Admin
|
39
|
+
class PostsController < ApplicationController
|
40
|
+
include Administrate::Punditize
|
41
|
+
|
42
|
+
def policy_namespace
|
43
|
+
[:admin]
|
41
44
|
end
|
45
|
+
end
|
46
|
+
end
|
42
47
|
|
43
|
-
|
44
|
-
|
48
|
+
# app/policies/admin/post_policy.rb
|
49
|
+
module Admin
|
50
|
+
class PostPolicy < ApplicationPolicy
|
51
|
+
class Scope < Scope
|
52
|
+
def resolve
|
53
|
+
scope.where(owner: user)
|
54
|
+
end
|
45
55
|
end
|
46
56
|
end
|
47
57
|
end
|
@@ -113,8 +113,8 @@ association `belongs_to :country`, from your model.
|
|
113
113
|
|
114
114
|
**Field::HasMany**
|
115
115
|
|
116
|
-
`:limit` -
|
117
|
-
`5`.
|
116
|
+
`:limit` - The number of resources (paginated) to display in the show view. To disable pagination,
|
117
|
+
set this to `0` or `false`. Default is `5`.
|
118
118
|
|
119
119
|
`:sort_by` - What to sort the association by in the show view.
|
120
120
|
|
@@ -128,6 +128,10 @@ association `belongs_to :country`, from your model.
|
|
128
128
|
|
129
129
|
**Field::HasOne**
|
130
130
|
|
131
|
+
`:order` - Specifies the column used to order the records. It will apply both in
|
132
|
+
the table views and in the dropdown menu on the record forms.
|
133
|
+
You can set multiple columns as well with direction. E.g.: `"name, email DESC"`.
|
134
|
+
|
131
135
|
`:searchable` - Specify if the attribute should be considered when searching.
|
132
136
|
Default is `false`.
|
133
137
|
|
@@ -218,25 +222,31 @@ objects to display as.
|
|
218
222
|
|
219
223
|
**Field::Select**
|
220
224
|
|
221
|
-
`:collection` -
|
222
|
-
an array or an object responding to `:call`. Defaults to `[]`.
|
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
|
+
`:collection` - The options available to select. The format is the same as for Rails's own [`options_for_select`](https://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-options_for_select).
|
225
226
|
|
226
|
-
For example:
|
227
|
+
If the given value responds to `call`, this will be called and the result used instead. The call will receive an instance of the field as argument. For example:
|
227
228
|
|
228
229
|
```ruby
|
229
|
-
|
230
|
-
collection:
|
230
|
+
confirmation: Field::Select.with_options(
|
231
|
+
collection: ->(field) {
|
232
|
+
person = field.resource
|
233
|
+
{
|
234
|
+
"no, #{person.name}" => "opt0",
|
235
|
+
"yes, #{person.name}" => "opt1",
|
236
|
+
"absolutely, #{person.name}" => "opt2",
|
237
|
+
}
|
238
|
+
},
|
231
239
|
)
|
232
|
-
|
233
240
|
```
|
234
241
|
|
242
|
+
Administrate will detect if the attribute is an `ActiveRecord::Enum` and extract the available options. Note that if a `collection` is provided it will take precedence.
|
243
|
+
|
244
|
+
If no collection is provided and no enum can be detected, the list of options will be empty.
|
245
|
+
|
235
246
|
`:searchable` - Specify if the attribute should be considered when searching.
|
236
247
|
Default is `true`.
|
237
248
|
|
238
|
-
`:include_blank` -
|
239
|
-
blank option. Default is `false`.
|
249
|
+
`:include_blank` - Similar to [the option of the same name accepted by Rails helpers](https://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html). If provided, a "blank" option will be added first to the list of options, with the value of `include_blank` as label.
|
240
250
|
|
241
251
|
**Field::String**
|
242
252
|
|
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
|
6
|
+
applications version 6.0 or greater. We support Ruby 2.7 and up.
|
7
7
|
|
8
8
|
First, add the following to your Gemfile:
|
9
9
|
|
@@ -135,7 +135,7 @@ records.
|
|
135
135
|
|
136
136
|
## A working example
|
137
137
|
|
138
|
-
The [Administrate demo app](/admin)
|
138
|
+
The [Administrate demo app](https://administrate-demo.herokuapp.com/admin)
|
139
139
|
includes an example of custom search in the "Log Entries" dashboard.
|
140
140
|
In this app, each `LogEntry` instance has a polymorphic `belongs_to`
|
141
141
|
association to a `:logeable`. Logeables are other models for which logs can be
|
@@ -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,12 @@ 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.map do |attr|
|
71
|
+
def permitted_attributes(action = nil)
|
72
|
+
form_attributes(action).map do |attr|
|
67
73
|
attribute_types[attr].permitted_attribute(
|
68
74
|
attr,
|
69
75
|
resource_class: self.class.model,
|
76
|
+
action: action,
|
70
77
|
)
|
71
78
|
end.uniq
|
72
79
|
end
|
@@ -7,6 +7,10 @@ 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
|
@@ -49,10 +53,16 @@ module Administrate
|
|
49
53
|
end
|
50
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
|
|
@@ -23,12 +23,15 @@ module Administrate
|
|
23
23
|
|
24
24
|
def associated_resource_options
|
25
25
|
candidate_resources.map do |resource|
|
26
|
-
[
|
26
|
+
[
|
27
|
+
display_candidate_resource(resource),
|
28
|
+
resource.send(association_primary_key),
|
29
|
+
]
|
27
30
|
end
|
28
31
|
end
|
29
32
|
|
30
33
|
def selected_option
|
31
|
-
data
|
34
|
+
data&.send(association_primary_key)
|
32
35
|
end
|
33
36
|
|
34
37
|
def include_blank_option
|
@@ -30,21 +30,28 @@ module Administrate
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def associated_resource_options
|
33
|
-
candidate_resources.map do |
|
34
|
-
[
|
33
|
+
candidate_resources.map do |associated_resource|
|
34
|
+
[
|
35
|
+
display_candidate_resource(associated_resource),
|
36
|
+
associated_resource.send(association_primary_key),
|
37
|
+
]
|
35
38
|
end
|
36
39
|
end
|
37
40
|
|
38
41
|
def selected_options
|
39
42
|
return if data.empty?
|
40
43
|
|
41
|
-
data.map { |object| object.send(
|
44
|
+
data.map { |object| object.send(association_primary_key) }
|
42
45
|
end
|
43
46
|
|
44
47
|
def limit
|
45
48
|
options.fetch(:limit, DEFAULT_LIMIT)
|
46
49
|
end
|
47
50
|
|
51
|
+
def paginate?
|
52
|
+
limit.respond_to?(:positive?) ? limit.positive? : limit.present?
|
53
|
+
end
|
54
|
+
|
48
55
|
def permitted_attribute
|
49
56
|
self.class.permitted_attribute(
|
50
57
|
attribute,
|
@@ -53,12 +60,15 @@ module Administrate
|
|
53
60
|
end
|
54
61
|
|
55
62
|
def resources(page = 1, order = self.order)
|
56
|
-
resources = order.apply(data)
|
63
|
+
resources = order.apply(data)
|
64
|
+
if paginate?
|
65
|
+
resources = resources.page(page).per(limit)
|
66
|
+
end
|
57
67
|
includes.any? ? resources.includes(*includes) : resources
|
58
68
|
end
|
59
69
|
|
60
70
|
def more_than_limit?
|
61
|
-
data.count(:all) > limit
|
71
|
+
paginate? && data.count(:all) > limit
|
62
72
|
end
|
63
73
|
|
64
74
|
def data
|
@@ -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
|
@@ -5,8 +5,10 @@ module Administrate
|
|
5
5
|
@resource = resource
|
6
6
|
|
7
7
|
case resource
|
8
|
-
when
|
8
|
+
when String, Symbol
|
9
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}")
|
10
12
|
else
|
11
13
|
super(
|
12
14
|
"Not allowed to perform #{action.inspect} on the given " +
|
data/lib/administrate/order.rb
CHANGED
@@ -52,11 +52,16 @@ module Administrate
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def order_by_association(relation)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
case relation_type(relation)
|
56
|
+
when :has_many
|
57
|
+
order_by_count(relation)
|
58
|
+
when :belongs_to
|
59
|
+
order_by_belongs_to(relation)
|
60
|
+
when :has_one
|
61
|
+
order_by_has_one(relation)
|
62
|
+
else
|
63
|
+
relation
|
64
|
+
end
|
60
65
|
end
|
61
66
|
|
62
67
|
def order_by_count(relation)
|
@@ -68,20 +73,36 @@ module Administrate
|
|
68
73
|
reorder(Arel.sql(query))
|
69
74
|
end
|
70
75
|
|
71
|
-
def
|
72
|
-
|
76
|
+
def order_by_belongs_to(relation)
|
77
|
+
if ordering_by_association_column?(relation)
|
78
|
+
order_by_attribute(relation)
|
79
|
+
else
|
80
|
+
order_by_id(relation)
|
81
|
+
end
|
73
82
|
end
|
74
83
|
|
75
|
-
def
|
84
|
+
def order_by_has_one(relation)
|
76
85
|
if ordering_by_association_column?(relation)
|
77
|
-
relation
|
78
|
-
attribute.to_sym,
|
79
|
-
).reorder(Arel.sql(order_by_attribute_query))
|
86
|
+
order_by_attribute(relation)
|
80
87
|
else
|
81
|
-
|
88
|
+
order_by_association_id(relation)
|
82
89
|
end
|
83
90
|
end
|
84
91
|
|
92
|
+
def order_by_attribute(relation)
|
93
|
+
relation.joins(
|
94
|
+
attribute.to_sym,
|
95
|
+
).reorder(Arel.sql(order_by_attribute_query))
|
96
|
+
end
|
97
|
+
|
98
|
+
def order_by_id(relation)
|
99
|
+
relation.reorder(Arel.sql(order_by_id_query(relation)))
|
100
|
+
end
|
101
|
+
|
102
|
+
def order_by_association_id(relation)
|
103
|
+
relation.reorder(Arel.sql(order_by_association_id_query))
|
104
|
+
end
|
105
|
+
|
85
106
|
def ordering_by_association_column?(relation)
|
86
107
|
association_attribute &&
|
87
108
|
column_exist?(
|
@@ -97,16 +118,16 @@ module Administrate
|
|
97
118
|
"#{relation.table_name}.#{foreign_key(relation)} #{direction}"
|
98
119
|
end
|
99
120
|
|
100
|
-
def
|
101
|
-
"#{
|
121
|
+
def order_by_association_id_query
|
122
|
+
"#{association_table_name}.id #{direction}"
|
102
123
|
end
|
103
124
|
|
104
|
-
def
|
105
|
-
|
125
|
+
def order_by_attribute_query
|
126
|
+
"#{association_table_name}.#{association_attribute} #{direction}"
|
106
127
|
end
|
107
128
|
|
108
|
-
def
|
109
|
-
reflect_association(relation).macro
|
129
|
+
def relation_type(relation)
|
130
|
+
reflect_association(relation).macro
|
110
131
|
end
|
111
132
|
|
112
133
|
def reflect_association(relation)
|
@@ -116,5 +137,9 @@ module Administrate
|
|
116
137
|
def foreign_key(relation)
|
117
138
|
reflect_association(relation).foreign_key
|
118
139
|
end
|
140
|
+
|
141
|
+
def association_table_name
|
142
|
+
attribute.tableize
|
143
|
+
end
|
119
144
|
end
|
120
145
|
end
|
@@ -11,13 +11,6 @@ module Administrate
|
|
11
11
|
attr_reader :resource
|
12
12
|
|
13
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
14
|
dashboard.form_attributes(action).map do |attribute|
|
22
15
|
attribute_field(dashboard, resource, attribute, :form)
|
23
16
|
end
|
data/lib/administrate/search.rb
CHANGED
data/lib/administrate/version.rb
CHANGED
@@ -5,7 +5,12 @@ require "administrate/namespace"
|
|
5
5
|
module Administrate
|
6
6
|
class ViewGenerator < Rails::Generators::Base
|
7
7
|
include Administrate::GeneratorHelpers
|
8
|
-
class_option
|
8
|
+
class_option(
|
9
|
+
:namespace,
|
10
|
+
type: :string,
|
11
|
+
desc: "Namespace where the admin dashboards live",
|
12
|
+
default: "admin",
|
13
|
+
)
|
9
14
|
|
10
15
|
def self.template_source_path
|
11
16
|
File.expand_path(
|
@@ -27,7 +27,12 @@ module Administrate
|
|
27
27
|
COLLECTION_ATTRIBUTE_LIMIT = 4
|
28
28
|
READ_ONLY_ATTRIBUTES = %w[id created_at updated_at]
|
29
29
|
|
30
|
-
class_option
|
30
|
+
class_option(
|
31
|
+
:namespace,
|
32
|
+
type: :string,
|
33
|
+
desc: "Namespace where the admin dashboards live",
|
34
|
+
default: "admin",
|
35
|
+
)
|
31
36
|
|
32
37
|
source_root File.expand_path("../templates", __FILE__)
|
33
38
|
|
@@ -36,11 +36,11 @@ module <%= namespace.to_s.camelize %>
|
|
36
36
|
#
|
37
37
|
# def resource_params
|
38
38
|
# params.require(resource_class.model_name.param_key).
|
39
|
-
# permit(dashboard.permitted_attributes).
|
39
|
+
# permit(dashboard.permitted_attributes(action_name)).
|
40
40
|
# transform_values { |value| value == "" ? nil : value }
|
41
41
|
# end
|
42
42
|
|
43
|
-
# See https://administrate-
|
43
|
+
# See https://administrate-demo.herokuapp.com/customizing_controller_actions
|
44
44
|
# for more information
|
45
45
|
end
|
46
46
|
end
|
@@ -14,7 +14,12 @@ module Administrate
|
|
14
14
|
include Administrate::GeneratorHelpers
|
15
15
|
source_root File.expand_path("../templates", __FILE__)
|
16
16
|
|
17
|
-
class_option
|
17
|
+
class_option(
|
18
|
+
:namespace,
|
19
|
+
type: :string,
|
20
|
+
desc: "Namespace where the admin dashboards will live",
|
21
|
+
default: "admin",
|
22
|
+
)
|
18
23
|
|
19
24
|
def run_routes_generator
|
20
25
|
if dashboard_resources.none?
|
@@ -7,13 +7,19 @@ end
|
|
7
7
|
require "rails/generators/base"
|
8
8
|
require "administrate/generator_helpers"
|
9
9
|
require "administrate/namespace"
|
10
|
+
require "generators/administrate/test_record"
|
10
11
|
|
11
12
|
module Administrate
|
12
13
|
module Generators
|
13
14
|
class RoutesGenerator < Rails::Generators::Base
|
14
15
|
include Administrate::GeneratorHelpers
|
15
16
|
source_root File.expand_path("../templates", __FILE__)
|
16
|
-
class_option
|
17
|
+
class_option(
|
18
|
+
:namespace,
|
19
|
+
type: :string,
|
20
|
+
desc: "Namespace where the admin dashboards live",
|
21
|
+
default: "admin",
|
22
|
+
)
|
17
23
|
|
18
24
|
def insert_dashboard_routes
|
19
25
|
if valid_dashboard_models.any?
|
@@ -55,7 +61,10 @@ module Administrate
|
|
55
61
|
end
|
56
62
|
|
57
63
|
def database_models
|
58
|
-
ActiveRecord::Base.descendants.
|
64
|
+
ActiveRecord::Base.descendants.
|
65
|
+
reject(&:abstract_class?).
|
66
|
+
reject { |k| k < Administrate::Generators::TestRecord }.
|
67
|
+
sort_by(&:to_s)
|
59
68
|
end
|
60
69
|
|
61
70
|
def invalid_dashboard_models
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Administrate
|
2
|
+
module Generators
|
3
|
+
# This class serves only to work around a strange behaviour in Rails 7
|
4
|
+
# with Ruby 3.
|
5
|
+
#
|
6
|
+
# After running the spec for DashboardGenerator, the fake models that
|
7
|
+
# it generates (eg: Foo, Shipment) linger around despite being removed
|
8
|
+
# explicitly. This causes RouteGenerator to take them into
|
9
|
+
# account and generate routes for them, which its spec doesn't expect,
|
10
|
+
# causing a spec failure.
|
11
|
+
#
|
12
|
+
# To avoid this, the spec for DashboardGenerator defines its fake models
|
13
|
+
# as children of TestRecord. Then RoutesGenerator explicitly filters
|
14
|
+
# child classes of TestRecord when figuring out what models exist.
|
15
|
+
#
|
16
|
+
# Discussion at https://github.com/thoughtbot/administrate/pull/2324
|
17
|
+
class TestRecord < ApplicationRecord
|
18
|
+
self.abstract_class = true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: administrate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.19.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Charlton
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-07-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: actionpack
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- Rakefile
|
133
133
|
- app/assets/javascripts/administrate/application.js
|
134
134
|
- app/assets/javascripts/administrate/components/associative.js
|
135
|
+
- app/assets/javascripts/administrate/components/select.js
|
135
136
|
- app/assets/javascripts/administrate/components/table.js
|
136
137
|
- app/assets/stylesheets/administrate/application.scss
|
137
138
|
- app/assets/stylesheets/administrate/base/_forms.scss
|
@@ -314,6 +315,7 @@ files:
|
|
314
315
|
- lib/generators/administrate/install/templates/application_controller.rb.erb
|
315
316
|
- lib/generators/administrate/routes/routes_generator.rb
|
316
317
|
- lib/generators/administrate/routes/templates/routes.rb.erb
|
318
|
+
- lib/generators/administrate/test_record.rb
|
317
319
|
- lib/generators/administrate/views/edit_generator.rb
|
318
320
|
- lib/generators/administrate/views/field_generator.rb
|
319
321
|
- lib/generators/administrate/views/form_generator.rb
|
@@ -343,7 +345,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
343
345
|
- !ruby/object:Gem::Version
|
344
346
|
version: '0'
|
345
347
|
requirements: []
|
346
|
-
rubygems_version: 3.
|
348
|
+
rubygems_version: 3.4.14
|
347
349
|
signing_key:
|
348
350
|
specification_version: 4
|
349
351
|
summary: A Rails engine for creating super-flexible admin dashboards
|