administrate 0.18.0 → 0.19.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/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
|