administrate 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of administrate might be problematic. Click here for more details.

Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/app/assets/stylesheets/administrate/components/_cells.scss +2 -6
  3. data/app/assets/stylesheets/docs.scss +1 -0
  4. data/app/controllers/administrate/application_controller.rb +35 -3
  5. data/app/controllers/concerns/administrate/punditize.rb +36 -0
  6. data/app/helpers/administrate/application_helper.rb +9 -4
  7. data/app/views/administrate/application/_collection.html.erb +9 -7
  8. data/app/views/administrate/application/_form.html.erb +5 -2
  9. data/app/views/administrate/application/_navigation.html.erb +1 -1
  10. data/app/views/administrate/application/edit.html.erb +3 -3
  11. data/app/views/administrate/application/index.html.erb +5 -2
  12. data/app/views/administrate/application/new.html.erb +6 -1
  13. data/app/views/administrate/application/show.html.erb +3 -3
  14. data/app/views/fields/has_many/_index.html.erb +1 -1
  15. data/app/views/fields/polymorphic/_form.html.erb +11 -6
  16. data/app/views/fields/polymorphic/_show.html.erb +8 -4
  17. data/config/locales/administrate.ar.yml +6 -6
  18. data/config/locales/administrate.bs.yml +27 -0
  19. data/config/locales/administrate.ca.yml +28 -0
  20. data/config/locales/administrate.da.yml +6 -6
  21. data/config/locales/administrate.de.yml +8 -8
  22. data/config/locales/administrate.en.yml +6 -6
  23. data/config/locales/administrate.es.yml +6 -6
  24. data/config/locales/administrate.fr.yml +6 -6
  25. data/config/locales/administrate.it.yml +6 -6
  26. data/config/locales/administrate.ja.yml +6 -6
  27. data/config/locales/administrate.ko.yml +6 -6
  28. data/config/locales/administrate.nl.yml +6 -6
  29. data/config/locales/administrate.pl.yml +6 -6
  30. data/config/locales/administrate.pt-BR.yml +6 -6
  31. data/config/locales/administrate.pt.yml +6 -6
  32. data/config/locales/administrate.ru.yml +6 -6
  33. data/config/locales/administrate.sv.yml +6 -6
  34. data/config/locales/administrate.uk.yml +6 -6
  35. data/config/locales/administrate.vi.yml +6 -6
  36. data/config/locales/administrate.zh-CN.yml +6 -6
  37. data/config/locales/administrate.zh-TW.yml +6 -6
  38. data/docs/authorization.md +69 -0
  39. data/docs/customizing_attribute_partials.md +20 -1
  40. data/docs/customizing_dashboards.md +54 -0
  41. data/docs/getting_started.md +82 -1
  42. data/lib/administrate/field/associative.rb +4 -0
  43. data/lib/administrate/field/base.rb +1 -1
  44. data/lib/administrate/field/belongs_to.rb +4 -3
  45. data/lib/administrate/field/date_time.rb +13 -2
  46. data/lib/administrate/field/deferred.rb +6 -5
  47. data/lib/administrate/field/has_many.rb +2 -2
  48. data/lib/administrate/field/has_one.rb +16 -8
  49. data/lib/administrate/field/polymorphic.rb +41 -3
  50. data/lib/administrate/order.rb +38 -5
  51. data/lib/administrate/resource_resolver.rb +2 -2
  52. data/lib/administrate/search.rb +1 -1
  53. data/lib/administrate/version.rb +1 -1
  54. data/lib/generators/administrate/dashboard/USAGE +1 -1
  55. data/lib/generators/administrate/dashboard/dashboard_generator.rb +7 -1
  56. data/lib/generators/administrate/dashboard/templates/controller.rb.erb +2 -2
  57. data/lib/generators/administrate/install/install_generator.rb +13 -6
  58. data/lib/generators/administrate/install/templates/{application_controller.rb → application_controller.rb.erb} +1 -1
  59. data/lib/generators/administrate/routes/routes_generator.rb +5 -0
  60. data/lib/generators/administrate/routes/templates/routes.rb.erb +1 -1
  61. data/lib/generators/administrate/views/field_generator.rb +19 -5
  62. metadata +8 -4
@@ -5,8 +5,9 @@ zh-TW:
5
5
  confirm: 確定?
6
6
  destroy: 刪除
7
7
  edit: 編輯
8
- show: 檢視
9
- new: 新增
8
+ edit_resource: 編輯 %{name}
9
+ show_resource: 檢視 %{name}
10
+ new_resource: 新增 %{name}
10
11
  back: 返回
11
12
  controller:
12
13
  create:
@@ -19,10 +20,9 @@ zh-TW:
19
20
  has_many:
20
21
  more: 顯示 %{total_count} 筆中的 %{count} 筆資料
21
22
  none: 無
22
- polymorphic:
23
- not_supported: 表單尚未支援 Polymorphic 關聯。
24
- has_one:
25
- not_supported: 表單尚未支援 HasOne 關聯。
23
+ form:
24
+ error: error
25
+ errors: "%{pluralized_errors} prohibited this %{resource_name} from being saved:"
26
26
  search:
27
27
  clear: 清除搜索
28
28
  label: 搜索 %{resource}
@@ -0,0 +1,69 @@
1
+ # Authorization
2
+
3
+ The default configuration of Administrate is "authenticate-only" - once a
4
+ user is authenticated, that user has access to every action of every object.
5
+
6
+ You can add more fine-grained authorization by overriding methods in the
7
+ controller.
8
+
9
+ ## Using Pundit
10
+
11
+ If your app already uses [Pundit](https://github.com/elabs/pundit) for
12
+ authorization, you just need to add one line to your
13
+ `Admin::ApplicationController`:
14
+
15
+ ```ruby
16
+ include Administrate::Punditize
17
+ ```
18
+
19
+ This will use all the policies from your main app to determine if the
20
+ current user is able to view a given record or perform a given action.
21
+
22
+ ### Further limiting scope
23
+
24
+ You may want to limit the scope for a given user beyond what they
25
+ technically have access to see in the main app. For example, a user may
26
+ have all public records in their scope, but you want to only show *their*
27
+ records in the admin interface to reduce confusion.
28
+
29
+ In this case, you can add an additional `resolve_admin` to your policy's
30
+ scope and Administrate will use this instead of the `resolve` method.
31
+
32
+ For example:
33
+
34
+ ```ruby
35
+ class PostPolicy < ApplicationPolicy
36
+ class Scope < Scope
37
+ def resolve
38
+ scope.all
39
+ end
40
+
41
+ def resolve_admin
42
+ scope.where(owner: user)
43
+ end
44
+ end
45
+ end
46
+ ```
47
+
48
+ ## Authorization without Pundit
49
+
50
+ If you use a different authorization library, or you want to roll your own,
51
+ you just need to override a few methods in your controllers or
52
+ `Admin::ApplicationController`. For example:
53
+
54
+ ```ruby
55
+ # Limit the scope of the given resource
56
+ def scoped_resource
57
+ super.where(user: current_user)
58
+ end
59
+
60
+ # Raise an exception if the user is not permitted to access this resource
61
+ def authorize_resource(resource)
62
+ raise "Erg!" unless show_action?(params[:action], resource)
63
+ end
64
+
65
+ # Hide links to actions if the user is not allowed to do them
66
+ def show_action?(action, resource)
67
+ current_user.can? action, resource
68
+ end
69
+ ```
@@ -1,7 +1,20 @@
1
1
  # Customizing attribute partials
2
2
 
3
3
  Occasionally you might want to change how specific types of attributes appear
4
- across all dashboards.
4
+ across all dashboards. You can customize the following built in field types:
5
+
6
+ - `belongs_to`
7
+ - `boolean`
8
+ - `date_time`
9
+ - `email`
10
+ - `has_many`
11
+ - `has_one`
12
+ - `number`
13
+ - `polymporphic`
14
+ - `select`
15
+ - `string`
16
+ - `text`
17
+
5
18
  For example, you might want all `Number` values to round to three decimal points.
6
19
 
7
20
  To get started, run the appropriate rails generator:
@@ -16,6 +29,12 @@ This will generate three files:
16
29
  - `app/view/fields/number/_index.html.erb`
17
30
  - `app/view/fields/number/_show.html.erb`
18
31
 
32
+ You can generate the partials for all field types by passing `all` to the generator.
33
+
34
+ ```bash
35
+ rails generate administrate:views:field all
36
+ ```
37
+
19
38
  The generated templates will have documentation
20
39
  describing which variables are in scope.
21
40
  The rendering part of the partial will look like:
@@ -70,6 +70,16 @@ specify, including:
70
70
  Each of the `Field` types take a different set of options,
71
71
  which are specified through the `.with_options` class method:
72
72
 
73
+ **Field::BelongsTo**
74
+
75
+ `:order` - Specifies the order of the dropdown menu, can be ordered by more
76
+ than one column. e.g.: `"name, email DESC"`.
77
+
78
+ `:primary_key` - Specifies object's primary_key. Defaults to `:id`.
79
+
80
+ `:foreign_key` - Specifies the name of the foreign key directly.
81
+ Defaults to `:#{attribute}_id`.
82
+
73
83
  **Field::HasMany**
74
84
 
75
85
  `:limit` - Set the number of resources to display in the show view. Default is
@@ -79,6 +89,10 @@ which are specified through the `.with_options` class method:
79
89
 
80
90
  `:direction` - What direction the sort should be in, `:asc` (default) or `:desc`.
81
91
 
92
+ `:primary_key` - Specifies object's primary_key. Defaults to `:id`.
93
+
94
+ `:foreign_key` - Specifies the name of the foreign key directly. Defaults to `:#{attribute}_id`
95
+
82
96
  **Field::Number**
83
97
 
84
98
  `:decimals` - Set the number of decimals to display. Defaults to `0`.
@@ -105,6 +119,22 @@ Or, to display a distance in kilometers:
105
119
  )
106
120
  ```
107
121
 
122
+ **Field::Polymorphic**
123
+
124
+ `:classes` - Specify a list of classes whose objects will be used to populate select boxes for editing this polymorphic field.
125
+ Default is `[]`.
126
+
127
+ `:order` - What to sort the association by in the form select.
128
+ Default is `nil`.
129
+
130
+ **Field::DateTime**
131
+
132
+ `:format` - Specify what format, using `strftime` you would like `DateTime`
133
+ objects to display as.
134
+
135
+ `:timezone` - Specify which timezone `Date` and `DateTime` objects are based
136
+ in.
137
+
108
138
  **Field::Select**
109
139
 
110
140
  `:collection` - Specify the array or range to select from. Defaults to `[]`.
@@ -157,3 +187,27 @@ end
157
187
  ````
158
188
 
159
189
  [define your own]: /adding_custom_field_types
190
+
191
+ To change the dashboard name in sidebar menu, sub-header and search string use default ActiveRecord i18n translations for models:
192
+
193
+ ```yaml
194
+ en:
195
+ activerecord:
196
+ models:
197
+ customer:
198
+ one: Happy Customer
199
+ others: Happy Customers
200
+ ```
201
+
202
+ ## Customizing Actions
203
+
204
+ To enable or disable certain actions you could override `valid_action?` method in your dashboard controller like this:
205
+
206
+ ```ruby
207
+ # disable 'edit' and 'destroy' links
208
+ def valid_action?(name, resource = resource_class)
209
+ %w[edit destroy].exclude?(name.to_s) && super
210
+ end
211
+ ```
212
+
213
+ Action is one of `new`, `edit`, `show`, `destroy`.
@@ -29,6 +29,20 @@ The `Admin::ApplicationController` can be customized to add
29
29
  authentication logic, authorization, pagination,
30
30
  or other controller-level concerns.
31
31
 
32
+ You will also want to add a `root` route to show a dashboard when you go to `/admin`.
33
+
34
+ ```ruby
35
+ Rails.application.routes.draw do
36
+ namespace :admin do
37
+ # Add dashboard for your models here
38
+ resources :customers,
39
+ resources :orders
40
+
41
+ root to: "customers#index" # <--- Root route
42
+ end
43
+ end
44
+ ```
45
+
32
46
  The routes can be customized to show or hide
33
47
  different models on the dashboard.
34
48
 
@@ -59,10 +73,54 @@ namespace :admin do
59
73
  end
60
74
  ```
61
75
 
76
+ ## Keep Dashboards Updated as Model Attributes Change
77
+
78
+ If you've installed Administrate and generated dashboards and _then_
79
+ subsequently added attributes to your models you'll need to manually add
80
+ these additions (or removals) to your dashboards.
81
+
82
+ Example:
83
+
84
+ ```ruby
85
+ # app/dashboards/your_model_dashboard.rb
86
+
87
+ ATTRIBUTE_TYPES = {
88
+ # ...
89
+ the_new_attribute: Field::String,
90
+ # ...
91
+ }.freeze
92
+
93
+ SHOW_PAGE_ATTRIBUTES = [
94
+ # ...
95
+ :the_new_attribute,
96
+ # ...
97
+ ].freeze
98
+
99
+ FORM_ATTRIBUTES = [
100
+ # ...
101
+ :the_new_attribute,
102
+ # ...
103
+ ].freeze
104
+
105
+ COLLECTION_ATTRIBUTES = [
106
+ # ...
107
+ :the_new_attribute, # if you want it on the index, also.
108
+ # ...
109
+ ].freeze
110
+ ```
111
+
112
+ It's recommended that you make this change at the same time as you add the
113
+ attribute to the model.
114
+
115
+ The alternative way to handle this is to re-run `rails g administrate:install` and
116
+ carefully pick through the diffs. This latter method is probably more cumbersome.
117
+
62
118
  ## Rails API
63
119
 
64
120
  Since Rails 5.0, we've been able to have API only applications. Yet, sometimes
65
- we still want to have an admin. To get this working, please update this config:
121
+ we still want to have an admin.
122
+
123
+ To get this working, we recommend updating this config:
66
124
 
67
125
  ```ruby
68
126
  # config/application.rb
@@ -74,3 +132,26 @@ also don't use your `ApplicationController`. Instead, Administrate provides its
74
132
  own. Meaning you're free to specify `ActionController::API` as your parent
75
133
  controller to make sure no flash, session, or cookie middleware is used by your
76
134
  API.
135
+
136
+ Alternatively, if your application needs to have `config.api_only = true`, we recommend you add the following lines to your `config/application.rb`
137
+
138
+ ```ruby
139
+ # Enable Flash, Cookies, MethodOverride for Administrate Gem
140
+ config.middleware.use ActionDispatch::Flash
141
+ config.session_store :cookie_store
142
+ config.middleware.use ActionDispatch::Cookies
143
+ config.middleware.use ActionDispatch::Session::CookieStore, config.session_options
144
+ config.middleware.use ::Rack::MethodOverride
145
+ ```
146
+
147
+ You must also ensure that the all the required controller actions are available and accessible as routes since generators in API-only applications only generate some of the required actions. Here is an example:
148
+
149
+ ```ruby
150
+ # routes.rb
151
+ namespace :admin do
152
+ resources name, only: %i(index show new create edit update destroy)
153
+ end
154
+
155
+ # names_controller.rb
156
+ # Ensure each of those methods are defined
157
+ ```
@@ -24,6 +24,10 @@ module Administrate
24
24
  def primary_key
25
25
  options.fetch(:primary_key, :id)
26
26
  end
27
+
28
+ def foreign_key
29
+ options.fetch(:foreign_key, :"#{attribute}_id")
30
+ end
27
31
  end
28
32
  end
29
33
  end
@@ -24,7 +24,7 @@ module Administrate
24
24
  @options = options
25
25
  end
26
26
 
27
- def self.permitted_attribute(attr)
27
+ def self.permitted_attribute(attr, _options = nil)
28
28
  attr
29
29
  end
30
30
 
@@ -3,12 +3,12 @@ require_relative "associative"
3
3
  module Administrate
4
4
  module Field
5
5
  class BelongsTo < Associative
6
- def self.permitted_attribute(attr)
6
+ def self.permitted_attribute(attr, _options = nil)
7
7
  :"#{attr}_id"
8
8
  end
9
9
 
10
10
  def permitted_attribute
11
- self.class.permitted_attribute(attribute)
11
+ foreign_key
12
12
  end
13
13
 
14
14
  def associated_resource_options
@@ -24,7 +24,8 @@ module Administrate
24
24
  private
25
25
 
26
26
  def candidate_resources
27
- associated_class.all
27
+ order = options.delete(:order)
28
+ order ? associated_class.order(order) : associated_class.all
28
29
  end
29
30
 
30
31
  def display_candidate_resource(resource)
@@ -4,11 +4,18 @@ module Administrate
4
4
  module Field
5
5
  class DateTime < Base
6
6
  def date
7
- I18n.localize(data.to_date, format: format)
7
+ I18n.localize(
8
+ data.in_time_zone(timezone).to_date,
9
+ format: format,
10
+ )
8
11
  end
9
12
 
10
13
  def datetime
11
- I18n.localize(data, format: format, default: data)
14
+ I18n.localize(
15
+ data.in_time_zone(timezone),
16
+ format: format,
17
+ default: data,
18
+ )
12
19
  end
13
20
 
14
21
  private
@@ -16,6 +23,10 @@ module Administrate
16
23
  def format
17
24
  options.fetch(:format, :default)
18
25
  end
26
+
27
+ def timezone
28
+ options.fetch(:timezone, "UTC")
29
+ end
19
30
  end
20
31
  end
21
32
  end
@@ -25,11 +25,12 @@ module Administrate
25
25
  options.fetch(:searchable, deferred_class.searchable?)
26
26
  end
27
27
 
28
- delegate(
29
- :html_class,
30
- :permitted_attribute,
31
- to: :deferred_class,
32
- )
28
+ def permitted_attribute(attr, _options = nil)
29
+ options.fetch(:foreign_key,
30
+ deferred_class.permitted_attribute(attr, options))
31
+ end
32
+
33
+ delegate :html_class, to: :deferred_class
33
34
  end
34
35
  end
35
36
  end
@@ -7,8 +7,8 @@ module Administrate
7
7
  class HasMany < Associative
8
8
  DEFAULT_LIMIT = 5
9
9
 
10
- def self.permitted_attribute(attribute)
11
- { "#{attribute.to_s.singularize}_ids".to_sym => [] }
10
+ def self.permitted_attribute(attr, _options = nil)
11
+ { "#{attr.to_s.singularize}_ids".to_sym => [] }
12
12
  end
13
13
 
14
14
  def associated_collection
@@ -3,25 +3,33 @@ require_relative "associative"
3
3
  module Administrate
4
4
  module Field
5
5
  class HasOne < Associative
6
- def initialize(attribute, data, page, options = {})
7
- resolver = Administrate::ResourceResolver.new("admin/#{attribute}")
8
- @nested_form = Administrate::Page::Form.new(
6
+ def nested_form
7
+ @nested_form ||= Administrate::Page::Form.new(
9
8
  resolver.dashboard_class.new,
10
9
  data || resolver.resource_class.new,
11
10
  )
12
-
13
- super
14
11
  end
15
12
 
16
- def self.permitted_attribute(attr)
13
+ def self.permitted_attribute(attr, options = nil)
14
+ associated_class_name =
15
+ if options
16
+ options.fetch(:class_name, attr.to_s.singularize.camelcase)
17
+ else
18
+ attr
19
+ end
17
20
  related_dashboard_attributes =
18
- Administrate::ResourceResolver.new("admin/#{attr}").
21
+ Administrate::ResourceResolver.new("admin/#{associated_class_name}").
19
22
  dashboard_class.new.permitted_attributes + [:id]
20
23
 
21
24
  { "#{attr}_attributes": related_dashboard_attributes }
22
25
  end
23
26
 
24
- attr_reader :nested_form
27
+ private
28
+
29
+ def resolver
30
+ @resolver ||=
31
+ Administrate::ResourceResolver.new("admin/#{associated_class_name}")
32
+ end
25
33
  end
26
34
  end
27
35
  end