administrate 0.12.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/administrate/components/associative.js +5 -0
  3. data/app/assets/javascripts/administrate/components/date_time_picker.js +6 -2
  4. data/app/assets/javascripts/administrate/components/table.js +1 -1
  5. data/app/assets/stylesheets/administrate/base/_tables.scss +3 -0
  6. data/app/assets/stylesheets/administrate/components/_attributes.scss +4 -3
  7. data/app/assets/stylesheets/administrate/components/_buttons.scss +8 -0
  8. data/app/assets/stylesheets/administrate/components/_cells.scss +2 -0
  9. data/app/assets/stylesheets/administrate/components/_field-unit.scss +17 -4
  10. data/app/assets/stylesheets/administrate/components/_flashes.scss +0 -8
  11. data/app/assets/stylesheets/administrate/components/_main-content.scss +1 -0
  12. data/app/assets/stylesheets/administrate/components/_navigation.scss +2 -3
  13. data/app/assets/stylesheets/administrate/library/_variables.scss +10 -8
  14. data/app/controllers/administrate/application_controller.rb +29 -8
  15. data/app/helpers/administrate/application_helper.rb +32 -14
  16. data/app/views/administrate/application/_collection.html.erb +6 -4
  17. data/app/views/administrate/application/_form.html.erb +2 -2
  18. data/app/views/administrate/application/_navigation.html.erb +5 -3
  19. data/app/views/administrate/application/index.html.erb +2 -2
  20. data/app/views/administrate/application/show.html.erb +1 -1
  21. data/app/views/fields/belongs_to/_form.html.erb +3 -3
  22. data/app/views/fields/date/_form.html.erb +24 -0
  23. data/app/views/fields/date/_index.html.erb +21 -0
  24. data/app/views/fields/date/_show.html.erb +21 -0
  25. data/app/views/fields/has_one/_index.html.erb +1 -1
  26. data/app/views/fields/has_one/_show.html.erb +4 -4
  27. data/app/views/fields/number/_form.html.erb +1 -1
  28. data/app/views/fields/polymorphic/_show.html.erb +1 -1
  29. data/app/views/fields/select/_form.html.erb +21 -9
  30. data/app/views/fields/string/_show.html.erb +2 -2
  31. data/app/views/fields/text/_show.html.erb +2 -3
  32. data/app/views/fields/time/_form.html.erb +3 -2
  33. data/app/views/fields/time/_index.html.erb +3 -1
  34. data/app/views/fields/time/_show.html.erb +3 -1
  35. data/app/views/layouts/administrate/application.html.erb +1 -0
  36. data/config/locales/administrate.ar.yml +2 -0
  37. data/config/locales/administrate.bs.yml +2 -0
  38. data/config/locales/administrate.ca.yml +2 -0
  39. data/config/locales/administrate.da.yml +2 -0
  40. data/config/locales/administrate.de.yml +2 -0
  41. data/config/locales/administrate.en.yml +2 -0
  42. data/config/locales/administrate.es.yml +2 -0
  43. data/config/locales/administrate.fi.yml +30 -0
  44. data/config/locales/administrate.fr.yml +4 -2
  45. data/config/locales/administrate.id.yml +2 -0
  46. data/config/locales/administrate.it.yml +2 -0
  47. data/config/locales/administrate.ja.yml +2 -0
  48. data/config/locales/administrate.ko.yml +2 -0
  49. data/config/locales/administrate.nl.yml +7 -5
  50. data/config/locales/administrate.pl.yml +2 -0
  51. data/config/locales/administrate.pt-BR.yml +4 -2
  52. data/config/locales/administrate.pt.yml +4 -2
  53. data/config/locales/administrate.ru.yml +2 -0
  54. data/config/locales/{administrate.al.yml → administrate.sq.yml} +3 -1
  55. data/config/locales/administrate.sv.yml +2 -0
  56. data/config/locales/administrate.tr.yml +30 -0
  57. data/config/locales/administrate.uk.yml +2 -0
  58. data/config/locales/administrate.vi.yml +2 -0
  59. data/config/locales/administrate.zh-CN.yml +2 -0
  60. data/config/locales/administrate.zh-TW.yml +2 -0
  61. data/config/unicorn.rb +8 -13
  62. data/docs/adding_controllers_without_related_model.md +54 -0
  63. data/docs/adding_custom_field_types.md +3 -1
  64. data/docs/authentication.md +3 -1
  65. data/docs/authorization.md +5 -3
  66. data/docs/customizing_attribute_partials.md +4 -1
  67. data/docs/customizing_controller_actions.md +30 -1
  68. data/docs/customizing_dashboards.md +47 -35
  69. data/docs/customizing_page_views.md +18 -4
  70. data/docs/extending_administrate.md +27 -0
  71. data/docs/getting_started.md +35 -11
  72. data/docs/guides/hiding_dashboards_from_sidebar.md +19 -0
  73. data/docs/guides.md +5 -0
  74. data/docs/rails_api.md +5 -3
  75. data/lib/administrate/base_dashboard.rb +19 -10
  76. data/lib/administrate/custom_dashboard.rb +15 -0
  77. data/lib/administrate/engine.rb +7 -0
  78. data/lib/administrate/field/associative.rb +49 -5
  79. data/lib/administrate/field/base.rb +35 -9
  80. data/lib/administrate/field/belongs_to.rb +13 -3
  81. data/lib/administrate/field/date.rb +20 -0
  82. data/lib/administrate/field/deferred.rb +22 -3
  83. data/lib/administrate/field/has_many.rb +15 -2
  84. data/lib/administrate/field/has_one.rb +32 -12
  85. data/lib/administrate/field/number.rb +19 -2
  86. data/lib/administrate/field/polymorphic.rb +5 -5
  87. data/lib/administrate/field/select.rb +6 -1
  88. data/lib/administrate/namespace.rb +4 -0
  89. data/lib/administrate/order.rb +17 -7
  90. data/lib/administrate/page/base.rb +1 -3
  91. data/lib/administrate/page/form.rb +1 -1
  92. data/lib/administrate/resource_resolver.rb +1 -1
  93. data/lib/administrate/search.rb +26 -19
  94. data/lib/administrate/version.rb +1 -1
  95. data/lib/administrate/view_generator.rb +9 -3
  96. data/lib/administrate.rb +19 -0
  97. data/lib/generators/administrate/dashboard/dashboard_generator.rb +18 -14
  98. data/lib/generators/administrate/dashboard/templates/controller.rb.erb +20 -8
  99. data/lib/generators/administrate/dashboard/templates/dashboard.rb.erb +4 -4
  100. data/lib/generators/administrate/install/install_generator.rb +37 -1
  101. data/lib/generators/administrate/install/templates/application_controller.rb.erb +3 -3
  102. data/lib/generators/administrate/routes/routes_generator.rb +15 -25
  103. data/lib/generators/administrate/views/views_generator.rb +5 -4
  104. metadata +26 -29
  105. data/app/assets/javascripts/administrate/components/has_many_form.js +0 -3
@@ -1,4 +1,6 @@
1
- # Customizing Dashboards
1
+ ---
2
+ title: Customizing Dashboards
3
+ ---
2
4
 
3
5
  In order to customize which attributes get displayed for each resource,
4
6
  edit the dashboard file generated by the installation generator.
@@ -54,6 +56,7 @@ specify, including:
54
56
  - `Field::BelongsTo`
55
57
  - `Field::Boolean`
56
58
  - `Field::DateTime`
59
+ - `Field::Date`
57
60
  - `Field::Email`
58
61
  - `Field::HasMany`
59
62
  - `Field::HasOne`
@@ -76,21 +79,16 @@ which are specified through the `.with_options` class method:
76
79
  `:order` - Specifies the order of the dropdown menu, can be ordered by more
77
80
  than one column. e.g.: `"name, email DESC"`.
78
81
 
79
- `:primary_key` - Specifies object's primary_key. Defaults to `:id`.
80
-
81
- `:foreign_key` - Specifies the name of the foreign key directly.
82
- Defaults to `:#{attribute}_id`.
83
-
84
82
  `:scope` - Specifies a custom scope inside a callable. Useful for preloading.
85
83
  Example: `.with_options(scope: -> { MyModel.includes(:rel).limit(5) })`
86
84
 
87
- `:class_name` - Specifies the name of the associated class.
88
- Defaults to `:#{attribute}.to_s.singularize.camelcase`.
85
+ `:include_blank` - Specifies if the select element to be rendered should include
86
+ blank option. Default is `true`.
89
87
 
90
88
  `:searchable` - Specify if the attribute should be considered when searching.
91
89
  Default is `false`.
92
90
 
93
- `searchable_field` - Specify which column to use on the search, only applies
91
+ `searchable_fields` - Specify which columns to use on the search, only applies
94
92
  if `searchable` is `true`
95
93
 
96
94
  For example:
@@ -98,13 +96,19 @@ For example:
98
96
  ```ruby
99
97
  country: Field::BelongsTo.with_options(
100
98
  searchable: true,
101
- searchable_field: 'name',
99
+ searchable_fields: ['name'],
102
100
  )
103
101
  ```
104
102
 
105
103
  with this, you will be able to search through the column `name` from the
106
104
  association `belongs_to :country`, from your model.
107
105
 
106
+ `:primary_key` (deprecated) - Specifies the association's primary_key.
107
+
108
+ `:foreign_key` (deprecated) - Specifies the name of the foreign key directly.
109
+
110
+ `:class_name` (deprecated) - Specifies the name of the associated class.
111
+
108
112
  **Field::HasMany**
109
113
 
110
114
  `:limit` - Set the number of resources to display in the show view. Default is
@@ -114,22 +118,18 @@ association `belongs_to :country`, from your model.
114
118
 
115
119
  `:direction` - What direction the sort should be in, `:asc` (default) or `:desc`.
116
120
 
117
- `:primary_key` - Specifies object's primary_key. Defaults to `:id`.
121
+ `:primary_key` (deprecated) - Specifies object's primary_key.
118
122
 
119
- `:foreign_key` - Specifies the name of the foreign key directly. Defaults to `:#{attribute}_id`
123
+ `:foreign_key` (deprecated) - Specifies the name of the foreign key directly.
120
124
 
121
- `:class_name` - Specifies the name of the associated class.
122
- Defaults to `:#{attribute}.to_s.singularize.camelcase`.
125
+ `:class_name` (deprecated) - Specifies the name of the associated class.
123
126
 
124
127
  **Field::HasOne**
125
128
 
126
- `:class_name` - Specifies the name of the associated class.
127
- Defaults to `:#{attribute}.to_s.singularize.camelcase`.
128
-
129
129
  `:searchable` - Specify if the attribute should be considered when searching.
130
130
  Default is `false`.
131
131
 
132
- `searchable_field` - Specify which column to use on the search, only applies if
132
+ `searchable_fields` - Specify which columns to use on the search, only applies if
133
133
  `searchable` is `true`
134
134
 
135
135
  For example:
@@ -137,13 +137,15 @@ For example:
137
137
  ```ruby
138
138
  cities: Field::HasMany.with_options(
139
139
  searchable: true,
140
- searchable_field: 'name',
140
+ searchable_fields: ['name'],
141
141
  )
142
142
  ```
143
143
 
144
144
  with this, you will be able to search through the column `name` from the
145
145
  association `has_many :cities`, from your model.
146
146
 
147
+ `:class_name` (deprecated) - Specifies the name of the associated class.
148
+
147
149
  **Field::Number**
148
150
 
149
151
  `:searchable` - Specify if the attribute should be considered when searching.
@@ -156,6 +158,13 @@ more results than expected. Default is `false`.
156
158
 
157
159
  `:suffix` - Suffixes the number with a string. Defaults to `""`.
158
160
 
161
+ `:format` - Specify a hash which defines a formatter. This uses ActiveSupport
162
+ and works by by passing a hash that includes the formatter (`formatter`) and
163
+ the options for the formatter (`formatter_options`). Defaults to the locale's
164
+ delimiter when `formatter_options` does not include a `delimiter`. See the
165
+ example below. Note that currently only
166
+ `ActiveSupport::NumberHelper.number_to_delimited` is supported.
167
+
159
168
  For example, you might use the following to display U.S. currency:
160
169
 
161
170
  ```ruby
@@ -163,15 +172,25 @@ For example, you might use the following to display U.S. currency:
163
172
  prefix: "$",
164
173
  decimals: 2,
165
174
  )
175
+
176
+ # "$5.99"
166
177
  ```
167
178
 
168
- Or, to display a distance in kilometers:
179
+ Or, to display a distance in kilometers, using a space as the delimiter:
169
180
 
170
181
  ```ruby
171
- unit_price: Field::Number.with_options(
182
+ distance: Field::Number.with_options(
172
183
  suffix: " km",
173
184
  decimals: 2,
185
+ format: {
186
+ formatter: :number_to_delimited,
187
+ formatter_options: {
188
+ delimiter: ' ',
189
+ },
190
+ },
174
191
  )
192
+
193
+ # "2 000.00 km"
175
194
  ```
176
195
 
177
196
  **Field::Polymorphic**
@@ -190,9 +209,15 @@ objects to display as.
190
209
  `:timezone` - Specify which timezone `Date` and `DateTime` objects are based
191
210
  in.
192
211
 
212
+ **Field::Date**
213
+
214
+ `:format` - Specify what format, using `strftime` you would like `Date`
215
+ objects to display as.
216
+
193
217
  **Field::Select**
194
218
 
195
- `:collection` - Specify the array or range to select from. Defaults to `[]`.
219
+ `:collection` - Specify the options shown on the select field. It accept either
220
+ an array or an object responding to `:call`. Defaults to `[]`.
196
221
 
197
222
  `:searchable` - Specify if the attribute should be considered when searching.
198
223
  Default is `true`.
@@ -265,19 +290,6 @@ en:
265
290
  other: Happy Customers
266
291
  ```
267
292
 
268
- ## Customizing Actions
269
-
270
- To enable or disable certain actions you could override `valid_action?` method in your dashboard controller like this:
271
-
272
- ```ruby
273
- # disable 'edit' and 'destroy' links
274
- def valid_action?(name, resource = resource_class)
275
- %w[edit destroy].exclude?(name.to_s) && super
276
- end
277
- ```
278
-
279
- Action is one of `new`, `edit`, `show`, `destroy`.
280
-
281
293
  ## Collection Filters
282
294
 
283
295
  Resources can be filtered with pre-set filters. For example if we added:
@@ -1,11 +1,25 @@
1
- # Customizing page views
1
+ ---
2
+ title: Customizing page views
3
+ ---
2
4
 
3
- In order to change the appearance of any page,
4
- you can write custom Rails views.
5
+ You can provide replacements for any of Administrate's templates.
6
+ This way you can change the appearance of any page or element of
7
+ the interface.
8
+
9
+ In general, you can override any of the views under Administrate's
10
+ [/app/views][1].
11
+ For example, say that you want to customize the template used for flash
12
+ messages. You can provide your own as
13
+ `/app/views/administrate/application/_flashes.html.erb`, and it will replace
14
+ Administrate's own.
15
+
16
+ Figuring out which views are available and where can be repetitive. You can
17
+ spare yourself some effort by using the built-in view generators.
18
+
19
+ [1]: https://github.com/thoughtbot/administrate/tree/master/app/views
5
20
 
6
21
  ## Customizing for all resources
7
22
 
8
- The easiest way to get started is by using the built-in generators.
9
23
  In order to change the appearance of views for all resource types,
10
24
  call the generators with no arguments.
11
25
 
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: Extending Administrate
3
+ ---
4
+
5
+ Apart from the configuration described in these pages, it is possible to
6
+ extend Administrate's capabilities with the use of plugins. There are a
7
+ number of plugins available, many of which can be found at [RubyGems.org].
8
+ At the time of writing, these appear to be the most popular ones:
9
+
10
+ 1. [ActiveStorage support](https://github.com/Dreamersoul/administrate-field-active_storage)
11
+ 2. [Password field](https://github.com/valiot/administrate-field-password)
12
+ 3. [Enum field](https://github.com/Valiot/administrate-field-enum)
13
+ 4. [Nested has-many forms](https://github.com/nickcharlton/administrate-field-nested_has_many)
14
+ 5. [Belongs-to with Ajax search](https://github.com/fishbrain/administrate-field-belongs_to_search)
15
+
16
+ See many more at https://rubygems.org/gems/administrate/reverse_dependencies.
17
+
18
+ Please note that these plugins are written by third parties. We do not
19
+ have any control over them, and we cannot give any assurances as to how
20
+ well they perform their advertised functions.
21
+
22
+ You can write your own plugins too! We don't document this specifically,
23
+ but you can have a look at the existing plugins for some directions.
24
+ In general, Administrate tries to abide by Rails's conventions, so that
25
+ hopefully should help!
26
+
27
+ [RubyGems.org]: https://rubygems.org
@@ -1,16 +1,18 @@
1
- # Getting Started
1
+ ---
2
+ title: Getting Started
3
+ ---
2
4
 
3
5
  Administrate is released as a Ruby gem, and can be installed on Rails
4
- applications version 4.2 or greater.
6
+ applications version 5.0 or greater. We support Ruby 2.4 and up.
5
7
 
6
- Add the following to your Gemfile:
8
+ First, add the following to your Gemfile:
7
9
 
8
10
  ```ruby
9
11
  # Gemfile
10
12
  gem "administrate"
11
13
  ```
12
14
 
13
- Re-bundle, then run the installer:
15
+ Re-bundle with `bundle install`, then run the installer:
14
16
 
15
17
  ```bash
16
18
  $ rails generate administrate:install
@@ -35,7 +37,7 @@ You will also want to add a `root` route to show a dashboard when you go to `/ad
35
37
  Rails.application.routes.draw do
36
38
  namespace :admin do
37
39
  # Add dashboard for your models here
38
- resources :customers,
40
+ resources :customers
39
41
  resources :orders
40
42
 
41
43
  root to: "customers#index" # <--- Root route
@@ -54,6 +56,28 @@ Each `Admin::FooController` can be overwritten to specify custom behavior.
54
56
  Once you have Administrate installed,
55
57
  visit <http://localhost:3000/admin> to see your new dashboard in action.
56
58
 
59
+ ### Errors about assets?
60
+
61
+ If your apps uses Sprockets 4, you'll need to add Administrate's assets to
62
+ your `manifest.js` file. To do this, add these two lines to the file:
63
+
64
+ ```
65
+ //= link administrate/application.css
66
+ //= link administrate/application.js
67
+ ```
68
+
69
+ Otherwise, your app will show you this error:
70
+
71
+ ```
72
+ Asset `administrate/application.css` was not declared to be precompiled in production.
73
+ Declare links to your assets in `app/assets/config/manifest.js`.
74
+ ```
75
+
76
+ For more information on why this is necessary, see Richard Schneeman's article
77
+ ["Self Hosted Config: Introducing the Sprockets manifest.js"][]
78
+
79
+ [schneems]: https://www.schneems.com/2017/11/22/self-hosted-config-introducing-the-sprockets-manifestjs
80
+
57
81
  ## Create Additional Dashboards
58
82
 
59
83
  In order to create additional dashboards, pass in the resource name to
@@ -63,7 +87,7 @@ the dashboard generator. A dashboard and controller will be created.
63
87
  $ rails generate administrate:dashboard Foo
64
88
  ```
65
89
 
66
- Add a route for the new dashboard.
90
+ Then add a route for the new dashboard.
67
91
 
68
92
  ```ruby
69
93
  # config/routes.rb
@@ -84,8 +108,8 @@ rails generate administrate:install --namespace=supervisor
84
108
 
85
109
  ## Keep Dashboards Updated as Model Attributes Change
86
110
 
87
- If you've installed Administrate and generated dashboards and _then_
88
- subsequently added attributes to your models you'll need to manually add
111
+ If you've installed Administrate and generated dashboards and _then_
112
+ subsequently added attributes to your models you'll need to manually add
89
113
  these additions (or removals) to your dashboards.
90
114
 
91
115
  Example:
@@ -98,7 +122,7 @@ Example:
98
122
  the_new_attribute: Field::String,
99
123
  # ...
100
124
  }.freeze
101
-
125
+
102
126
  SHOW_PAGE_ATTRIBUTES = [
103
127
  # ...
104
128
  :the_new_attribute,
@@ -110,7 +134,7 @@ Example:
110
134
  :the_new_attribute,
111
135
  # ...
112
136
  ].freeze
113
-
137
+
114
138
  COLLECTION_ATTRIBUTES = [
115
139
  # ...
116
140
  :the_new_attribute, # if you want it on the index, also.
@@ -118,7 +142,7 @@ Example:
118
142
  ].freeze
119
143
  ```
120
144
 
121
- It's recommended that you make this change at the same time as you add the
145
+ It's recommended that you make this change at the same time as you add the
122
146
  attribute to the model.
123
147
 
124
148
  The alternative way to handle this is to re-run `rails g administrate:install`
@@ -0,0 +1,19 @@
1
+ ---
2
+ title: Hiding Dashboards from the Sidebar
3
+ ---
4
+
5
+ Resources can be removed form the sidebar by removing their index action from the routes. For example:
6
+
7
+ ```ruby
8
+ # config/routes.rb
9
+ Rails.application.routes.draw do
10
+ namespace :admin do
11
+ resources :line_items, except: :index
12
+ resources :orders
13
+ resources :products
14
+ root to: "customers#index"
15
+ end
16
+ end
17
+ ```
18
+
19
+ In this case, only Orders and Products will appear in the sidebar, while Line Items can still appear as an association.
data/docs/guides.md ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ title: Guides
3
+ ---
4
+
5
+ * [Hiding Dashboards from the Sidebar](./guides/hiding_dashboards_from_sidebar)
data/docs/rails_api.md CHANGED
@@ -1,7 +1,9 @@
1
- ## Rails API
1
+ ---
2
+ title: Rails API
3
+ ---
2
4
 
3
5
  Since Rails 5.0, we've been able to have API only applications. Yet, sometimes
4
- we still want to have an admin.
6
+ we still want to have an admin.
5
7
 
6
8
  To get this working, we recommend updating this config:
7
9
 
@@ -29,7 +31,7 @@ config.middleware.use ::Rack::MethodOverride
29
31
  ```
30
32
 
31
33
  You must also ensure that all the required controller actions are available
32
- and accessible as routes since generators in API-only applications only
34
+ and accessible as routes since generators in API-only applications only
33
35
  generate some of the required actions. Here is an example:
34
36
 
35
37
  ```ruby
@@ -1,6 +1,7 @@
1
1
  require "administrate/field/belongs_to"
2
2
  require "administrate/field/boolean"
3
3
  require "administrate/field/date_time"
4
+ require "administrate/field/date"
4
5
  require "administrate/field/email"
5
6
  require "administrate/field/has_many"
6
7
  require "administrate/field/has_one"
@@ -17,6 +18,18 @@ module Administrate
17
18
  class BaseDashboard
18
19
  include Administrate
19
20
 
21
+ DASHBOARD_SUFFIX = "Dashboard".freeze
22
+
23
+ class << self
24
+ def model
25
+ to_s.chomp(DASHBOARD_SUFFIX).classify.constantize
26
+ end
27
+
28
+ def resource_name(opts)
29
+ model.model_name.human(opts)
30
+ end
31
+ end
32
+
20
33
  def attribute_types
21
34
  self.class::ATTRIBUTE_TYPES
22
35
  end
@@ -43,7 +56,10 @@ module Administrate
43
56
 
44
57
  def permitted_attributes
45
58
  form_attributes.map do |attr|
46
- attribute_types[attr].permitted_attribute(attr)
59
+ attribute_types[attr].permitted_attribute(
60
+ attr,
61
+ resource_class: self.class.model,
62
+ )
47
63
  end.uniq
48
64
  end
49
65
 
@@ -73,18 +89,11 @@ module Administrate
73
89
  "Attribute #{attr} could not be found in #{self.class}::ATTRIBUTE_TYPES"
74
90
  end
75
91
 
76
- def association_classes
77
- @association_classes ||=
78
- ObjectSpace.each_object(Class).
79
- select { |klass| klass < Administrate::Field::Associative }
80
- end
81
-
82
92
  def attribute_includes(attributes)
83
93
  attributes.map do |key|
84
- field = self.class::ATTRIBUTE_TYPES[key]
94
+ field = attribute_type_for(key)
85
95
 
86
- next key if association_classes.include?(field)
87
- key if association_classes.include?(field.try(:deferred_class))
96
+ key if field.associative?
88
97
  end.compact
89
98
  end
90
99
  end
@@ -0,0 +1,15 @@
1
+ module Administrate
2
+ class CustomDashboard
3
+ include Administrate
4
+
5
+ class << self
6
+ def resource_name(_opts)
7
+ named_resource.pluralize.titleize
8
+ end
9
+
10
+ def resource(resource_name)
11
+ define_singleton_method(:named_resource) { resource_name }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -22,6 +22,13 @@ module Administrate
22
22
  @@javascripts = []
23
23
  @@stylesheets = []
24
24
 
25
+ initializer "administrate.assets.precompile" do |app|
26
+ app.config.assets.precompile += [
27
+ "administrate/application.js",
28
+ "administrate/application.css",
29
+ ]
30
+ end
31
+
25
32
  def self.add_javascript(script)
26
33
  @@javascripts << script
27
34
  end
@@ -3,30 +3,74 @@ require_relative "base"
3
3
  module Administrate
4
4
  module Field
5
5
  class Associative < Base
6
+ def self.foreign_key_for(resource_class, attr)
7
+ reflection(resource_class, attr).foreign_key
8
+ end
9
+
10
+ def self.associated_class(resource_class, attr)
11
+ reflection(resource_class, attr).klass
12
+ end
13
+
14
+ def self.associated_class_name(resource_class, attr)
15
+ reflection(resource_class, attr).class_name
16
+ end
17
+
18
+ def self.reflection(resource_class, attr)
19
+ resource_class.reflect_on_association(attr)
20
+ end
21
+
6
22
  def display_associated_resource
7
23
  associated_dashboard.display_resource(data)
8
24
  end
9
25
 
10
26
  def associated_class
11
- associated_class_name.constantize
27
+ if option_given?(:class_name)
28
+ associated_class_name.constantize
29
+ else
30
+ self.class.associated_class(resource.class, attribute)
31
+ end
12
32
  end
13
33
 
14
- protected
34
+ private
15
35
 
16
36
  def associated_dashboard
17
37
  "#{associated_class_name}Dashboard".constantize.new
18
38
  end
19
39
 
20
40
  def associated_class_name
21
- options.fetch(:class_name, attribute.to_s.singularize.camelcase)
41
+ if option_given?(:class_name)
42
+ deprecated_option(:class_name)
43
+ else
44
+ self.class.associated_class_name(
45
+ resource.class,
46
+ attribute,
47
+ )
48
+ end
22
49
  end
23
50
 
24
51
  def primary_key
25
- options.fetch(:primary_key, :id)
52
+ if option_given?(:primary_key)
53
+ deprecated_option(:primary_key)
54
+ else
55
+ :id
56
+ end
26
57
  end
27
58
 
28
59
  def foreign_key
29
- options.fetch(:foreign_key, :"#{attribute}_id")
60
+ if option_given?(:foreign_key)
61
+ deprecated_option(:foreign_key)
62
+ else
63
+ self.class.foreign_key_for(resource.class, attribute)
64
+ end
65
+ end
66
+
67
+ def option_given?(name)
68
+ options.key?(name)
69
+ end
70
+
71
+ def deprecated_option(name)
72
+ Administrate.warn_of_deprecated_option(name)
73
+ options.fetch(name)
30
74
  end
31
75
  end
32
76
  end
@@ -12,10 +12,22 @@ module Administrate
12
12
  field_type.dasherize
13
13
  end
14
14
 
15
+ def self.associative?
16
+ self < Associative
17
+ end
18
+
15
19
  def self.searchable?
16
20
  false
17
21
  end
18
22
 
23
+ def self.field_type
24
+ to_s.split("::").last.underscore
25
+ end
26
+
27
+ def self.permitted_attribute(attr, _options = nil)
28
+ attr
29
+ end
30
+
19
31
  def initialize(attribute, data, page, options = {})
20
32
  @attribute = attribute
21
33
  @data = data
@@ -24,10 +36,6 @@ module Administrate
24
36
  @options = options
25
37
  end
26
38
 
27
- def self.permitted_attribute(attr, _options = nil)
28
- attr
29
- end
30
-
31
39
  def html_class
32
40
  self.class.html_class
33
41
  end
@@ -40,15 +48,33 @@ module Administrate
40
48
  "/fields/#{self.class.field_type}/#{page}"
41
49
  end
42
50
 
43
- attr_reader :attribute, :data, :page, :resource
51
+ def required?
52
+ return false unless resource.class.respond_to?(:validators_on)
44
53
 
45
- protected
54
+ resource.class.validators_on(attribute).any? do |v|
55
+ next false unless v.class == ActiveRecord::Validations::PresenceValidator
46
56
 
47
- attr_reader :options
57
+ options = v.options
58
+ next false if options.include?(:if)
59
+ next false if options.include?(:unless)
48
60
 
49
- def self.field_type
50
- to_s.split("::").last.underscore
61
+ if on_option = options[:on]
62
+ if on_option == :create && !resource.persisted?
63
+ next true
64
+ end
65
+
66
+ if on_option == :update && resource.persisted?
67
+ next true
68
+ end
69
+
70
+ next false
71
+ end
72
+
73
+ true
74
+ end
51
75
  end
76
+
77
+ attr_reader :attribute, :data, :options, :page, :resource
52
78
  end
53
79
  end
54
80
  end
@@ -3,8 +3,14 @@ require_relative "associative"
3
3
  module Administrate
4
4
  module Field
5
5
  class BelongsTo < Associative
6
- def self.permitted_attribute(attr, _options = nil)
7
- :"#{attr}_id"
6
+ def self.permitted_attribute(attr, options = {})
7
+ resource_class = options[:resource_class]
8
+ if resource_class
9
+ foreign_key_for(resource_class, attr)
10
+ else
11
+ Administrate.warn_of_missing_resource_class
12
+ :"#{attr}_id"
13
+ end
8
14
  end
9
15
 
10
16
  def permitted_attribute
@@ -12,7 +18,7 @@ module Administrate
12
18
  end
13
19
 
14
20
  def associated_resource_options
15
- [nil] + candidate_resources.map do |resource|
21
+ candidate_resources.map do |resource|
16
22
  [display_candidate_resource(resource), resource.send(primary_key)]
17
23
  end
18
24
  end
@@ -21,6 +27,10 @@ module Administrate
21
27
  data && data.send(primary_key)
22
28
  end
23
29
 
30
+ def include_blank_option
31
+ options.fetch(:include_blank, true)
32
+ end
33
+
24
34
  private
25
35
 
26
36
  def candidate_resources