administrate 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/administrate/components/associative.js +1 -0
  3. data/app/assets/stylesheets/administrate/components/_attributes.scss +3 -2
  4. data/app/assets/stylesheets/administrate/components/_field-unit.scss +4 -0
  5. data/app/assets/stylesheets/administrate/components/_main-content.scss +1 -0
  6. data/app/controllers/administrate/application_controller.rb +11 -11
  7. data/app/helpers/administrate/application_helper.rb +10 -23
  8. data/app/views/administrate/application/_collection.html.erb +1 -1
  9. data/app/views/administrate/application/_form.html.erb +1 -1
  10. data/app/views/administrate/application/index.html.erb +2 -2
  11. data/app/views/administrate/application/show.html.erb +1 -1
  12. data/app/views/fields/belongs_to/_form.html.erb +3 -3
  13. data/app/views/fields/has_one/_index.html.erb +1 -1
  14. data/app/views/fields/has_one/_show.html.erb +4 -4
  15. data/app/views/fields/number/_form.html.erb +1 -1
  16. data/app/views/fields/polymorphic/_show.html.erb +1 -1
  17. data/app/views/fields/select/_form.html.erb +2 -2
  18. data/app/views/fields/time/_index.html.erb +3 -1
  19. data/app/views/fields/time/_show.html.erb +3 -1
  20. data/app/views/layouts/administrate/application.html.erb +1 -0
  21. data/config/locales/administrate.fi.yml +30 -0
  22. data/config/locales/administrate.fr.yml +2 -2
  23. data/config/locales/administrate.nl.yml +4 -4
  24. data/config/locales/administrate.pt-BR.yml +2 -2
  25. data/config/locales/administrate.pt.yml +3 -3
  26. data/config/locales/administrate.tr.yml +30 -0
  27. data/config/unicorn.rb +8 -13
  28. data/docs/adding_controllers_without_related_model.md +18 -0
  29. data/docs/customizing_dashboards.md +32 -16
  30. data/docs/extending_administrate.md +27 -0
  31. data/docs/getting_started.md +27 -5
  32. data/docs/guides.md +5 -0
  33. data/docs/guides/hiding_dashboards_from_sidebar.md +19 -0
  34. data/lib/administrate.rb +19 -0
  35. data/lib/administrate/base_dashboard.rb +5 -2
  36. data/lib/administrate/engine.rb +7 -0
  37. data/lib/administrate/field/associative.rb +48 -4
  38. data/lib/administrate/field/base.rb +26 -0
  39. data/lib/administrate/field/belongs_to.rb +13 -3
  40. data/lib/administrate/field/deferred.rb +7 -3
  41. data/lib/administrate/field/has_many.rb +15 -2
  42. data/lib/administrate/field/has_one.rb +28 -8
  43. data/lib/administrate/field/number.rb +19 -2
  44. data/lib/administrate/field/polymorphic.rb +1 -1
  45. data/lib/administrate/order.rb +3 -1
  46. data/lib/administrate/resource_resolver.rb +1 -1
  47. data/lib/administrate/search.rb +11 -8
  48. data/lib/administrate/version.rb +1 -1
  49. data/lib/administrate/view_generator.rb +7 -1
  50. data/lib/generators/administrate/dashboard/dashboard_generator.rb +3 -10
  51. data/lib/generators/administrate/dashboard/templates/dashboard.rb.erb +3 -3
  52. data/lib/generators/administrate/install/install_generator.rb +37 -1
  53. data/lib/generators/administrate/routes/routes_generator.rb +3 -13
  54. data/lib/generators/administrate/views/views_generator.rb +5 -4
  55. metadata +15 -25
  56. data/docs/contributing.md +0 -1
@@ -22,8 +22,8 @@ pt-BR:
22
22
  more: "Exibindo %{count} de %{total_count}"
23
23
  none: Nenhum
24
24
  form:
25
- error: error
26
- errors: "%{pluralized_errors} prohibited this %{resource_name} from being saved:"
25
+ error: erro
26
+ errors: "%{pluralized_errors} impediram %{resource_name} de ser gravado:"
27
27
  navigation:
28
28
  back_to_app: Voltar ao aplicativo
29
29
  search:
@@ -22,10 +22,10 @@ pt:
22
22
  more: "Mostrando %{count} de %{total_count}"
23
23
  none: Nenhum
24
24
  form:
25
- error: error
26
- errors: "%{pluralized_errors} prohibited this %{resource_name} from being saved:"
25
+ error: erro
26
+ errors: "%{pluralized_errors} impediram %{resource_name} de ser gravado:"
27
27
  navigation:
28
- back_to_app: Voltar ao aplicativo
28
+ back_to_app: Voltar à aplicação
29
29
  search:
30
30
  clear: Limpar pesquisa
31
31
  label: Pesquisa %{resource}
@@ -0,0 +1,30 @@
1
+ ---
2
+ tr:
3
+ administrate:
4
+ actions:
5
+ confirm: Emin misiniz?
6
+ destroy: Sil
7
+ edit: Düzenle
8
+ edit_resource: "%{name} Kaydını Düzenle"
9
+ show_resource: "%{name} Kaydını Göster"
10
+ new_resource: Yeni %{name}
11
+ back: Geri
12
+ controller:
13
+ create:
14
+ success: "%{resource} kaydı başarıyla yaratıldı."
15
+ destroy:
16
+ success: "%{resource} kaydı başarıyla silindi."
17
+ update:
18
+ success: "%{resource} kaydı başarıyla düzenlendi."
19
+ fields:
20
+ has_many:
21
+ more: Toplam %{total_count} kayıttan %{count} adedi gösteriliyor
22
+ none: Yok
23
+ form:
24
+ error: Hata
25
+ errors: "%{resource_name} kaydedilemedi: %{pluralized_errors}"
26
+ navigation:
27
+ back_to_app: Uygulamaya geri dön
28
+ search:
29
+ clear: Temizle
30
+ label: "%{resource} içerisinde ara"
data/config/unicorn.rb CHANGED
@@ -1,30 +1,25 @@
1
1
  # https://devcenter.heroku.com/articles/rails-unicorn
2
2
 
3
- worker_processes (ENV["UNICORN_WORKERS"] || 3).to_i
4
- timeout (ENV["UNICORN_TIMEOUT"] || 15).to_i
3
+ worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
4
+ timeout 15
5
5
  preload_app true
6
6
 
7
7
  before_fork do |_server, _worker|
8
8
  Signal.trap "TERM" do
9
- puts "Unicorn master intercepting TERM, sending myself QUIT instead"
9
+ puts "Unicorn master intercepting TERM and sending myself QUIT instead"
10
10
  Process.kill "QUIT", Process.pid
11
11
  end
12
12
 
13
- if defined? ActiveRecord::Base
13
+ defined?(ActiveRecord::Base) &&
14
14
  ActiveRecord::Base.connection.disconnect!
15
- end
16
15
  end
17
16
 
18
17
  after_fork do |_server, _worker|
19
18
  Signal.trap "TERM" do
20
- puts "Unicorn worker intercepting TERM, waiting for master to send QUIT"
19
+ puts "Unicorn worker intercepting TERM and doing nothing. " \
20
+ "Wait for master to send QUIT"
21
21
  end
22
22
 
23
- if defined? ActiveRecord::Base
24
- config = ActiveRecord::Base.configurations[Rails.env] ||
25
- Rails.application.config.database_configuration[Rails.env]
26
- config["reaping_frequency"] = (ENV["DB_REAPING_FREQUENCY"] || 10).to_i
27
- config["pool"] = (ENV["DB_POOL"] || 2).to_i
28
- ActiveRecord::Base.establish_connection(config)
29
- end
23
+ defined?(ActiveRecord::Base) &&
24
+ ActiveRecord::Base.establish_connection
30
25
  end
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Adding Controllers without a related Model
3
+ ---
4
+
1
5
  # Adding Controllers without a related Model
2
6
 
3
7
  Sometimes you may want to add a custom controller that has no resource
@@ -27,6 +31,20 @@ class StatDashboard < Administrate::CustomDashboard
27
31
  end
28
32
  ```
29
33
 
34
+ ```ruby
35
+ # app/controllers/admin/stats_controller.rb
36
+ module Admin
37
+ class StatsController < Admin::ApplicationController
38
+ def index
39
+ @stats = {
40
+ customer_count: Customer.count,
41
+ order_count: Order.count,
42
+ }
43
+ end
44
+ end
45
+ end
46
+ ```
47
+
30
48
  ```ruby
31
49
  # config/routes.rb
32
50
  namespace :admin do
@@ -79,16 +79,11 @@ which are specified through the `.with_options` class method:
79
79
  `:order` - Specifies the order of the dropdown menu, can be ordered by more
80
80
  than one column. e.g.: `"name, email DESC"`.
81
81
 
82
- `:primary_key` - Specifies object's primary_key. Defaults to `:id`.
83
-
84
- `:foreign_key` - Specifies the name of the foreign key directly.
85
- Defaults to `:#{attribute}_id`.
86
-
87
82
  `:scope` - Specifies a custom scope inside a callable. Useful for preloading.
88
83
  Example: `.with_options(scope: -> { MyModel.includes(:rel).limit(5) })`
89
84
 
90
- `:class_name` - Specifies the name of the associated class.
91
- 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`.
92
87
 
93
88
  `:searchable` - Specify if the attribute should be considered when searching.
94
89
  Default is `false`.
@@ -108,6 +103,12 @@ For example:
108
103
  with this, you will be able to search through the column `name` from the
109
104
  association `belongs_to :country`, from your model.
110
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
+
111
112
  **Field::HasMany**
112
113
 
113
114
  `:limit` - Set the number of resources to display in the show view. Default is
@@ -117,18 +118,14 @@ association `belongs_to :country`, from your model.
117
118
 
118
119
  `:direction` - What direction the sort should be in, `:asc` (default) or `:desc`.
119
120
 
120
- `:primary_key` - Specifies object's primary_key. Defaults to `:id`.
121
+ `:primary_key` (deprecated) - Specifies object's primary_key.
121
122
 
122
- `: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.
123
124
 
124
- `:class_name` - Specifies the name of the associated class.
125
- Defaults to `:#{attribute}.to_s.singularize.camelcase`.
125
+ `:class_name` (deprecated) - Specifies the name of the associated class.
126
126
 
127
127
  **Field::HasOne**
128
128
 
129
- `:class_name` - Specifies the name of the associated class.
130
- Defaults to `:#{attribute}.to_s.singularize.camelcase`.
131
-
132
129
  `:searchable` - Specify if the attribute should be considered when searching.
133
130
  Default is `false`.
134
131
 
@@ -147,6 +144,8 @@ For example:
147
144
  with this, you will be able to search through the column `name` from the
148
145
  association `has_many :cities`, from your model.
149
146
 
147
+ `:class_name` (deprecated) - Specifies the name of the associated class.
148
+
150
149
  **Field::Number**
151
150
 
152
151
  `:searchable` - Specify if the attribute should be considered when searching.
@@ -159,6 +158,13 @@ more results than expected. Default is `false`.
159
158
 
160
159
  `:suffix` - Suffixes the number with a string. Defaults to `""`.
161
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
+
162
168
  For example, you might use the following to display U.S. currency:
163
169
 
164
170
  ```ruby
@@ -166,15 +172,25 @@ For example, you might use the following to display U.S. currency:
166
172
  prefix: "$",
167
173
  decimals: 2,
168
174
  )
175
+
176
+ # "$5.99"
169
177
  ```
170
178
 
171
- Or, to display a distance in kilometers:
179
+ Or, to display a distance in kilometers, using a space as the delimiter:
172
180
 
173
181
  ```ruby
174
- unit_price: Field::Number.with_options(
182
+ distance: Field::Number.with_options(
175
183
  suffix: " km",
176
184
  decimals: 2,
185
+ format: {
186
+ formatter: :number_to_delimited,
187
+ formatter_options: {
188
+ delimiter: ' ',
189
+ },
190
+ },
177
191
  )
192
+
193
+ # "2 000.00 km"
178
194
  ```
179
195
 
180
196
  **Field::Polymorphic**
@@ -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
@@ -3,16 +3,16 @@ 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 4.2 or greater.
6
+ applications version 5.0 or greater. We support Ruby 2.4 and up.
7
7
 
8
- Add the following to your Gemfile:
8
+ First, add the following to your Gemfile:
9
9
 
10
10
  ```ruby
11
11
  # Gemfile
12
12
  gem "administrate"
13
13
  ```
14
14
 
15
- Re-bundle, then run the installer:
15
+ Re-bundle with `bundle install`, then run the installer:
16
16
 
17
17
  ```bash
18
18
  $ rails generate administrate:install
@@ -37,7 +37,7 @@ You will also want to add a `root` route to show a dashboard when you go to `/ad
37
37
  Rails.application.routes.draw do
38
38
  namespace :admin do
39
39
  # Add dashboard for your models here
40
- resources :customers,
40
+ resources :customers
41
41
  resources :orders
42
42
 
43
43
  root to: "customers#index" # <--- Root route
@@ -56,6 +56,28 @@ Each `Admin::FooController` can be overwritten to specify custom behavior.
56
56
  Once you have Administrate installed,
57
57
  visit <http://localhost:3000/admin> to see your new dashboard in action.
58
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
+
59
81
  ## Create Additional Dashboards
60
82
 
61
83
  In order to create additional dashboards, pass in the resource name to
@@ -65,7 +87,7 @@ the dashboard generator. A dashboard and controller will be created.
65
87
  $ rails generate administrate:dashboard Foo
66
88
  ```
67
89
 
68
- Add a route for the new dashboard.
90
+ Then add a route for the new dashboard.
69
91
 
70
92
  ```ruby
71
93
  # config/routes.rb
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)
@@ -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/lib/administrate.rb CHANGED
@@ -1,4 +1,23 @@
1
1
  require "administrate/engine"
2
2
 
3
3
  module Administrate
4
+ def self.warn_of_missing_resource_class
5
+ ActiveSupport::Deprecation.warn(
6
+ "Calling Field::Base.permitted_attribute without the option " +
7
+ ":resource_class is deprecated. If you are seeing this " +
8
+ "message, you are probably using a custom field type that" +
9
+ "does this. Please make sure to update it to a version that " +
10
+ "does not use a deprecated API",
11
+ )
12
+ end
13
+
14
+ def self.warn_of_deprecated_option(name)
15
+ ActiveSupport::Deprecation.warn(
16
+ "The option :#{name} is deprecated. " +
17
+ "Administrate should detect it automatically. " +
18
+ "Please file an issue at " +
19
+ "https://github.com/thoughtbot/administrate/issues " +
20
+ "if you think otherwise.",
21
+ )
22
+ end
4
23
  end
@@ -56,7 +56,10 @@ module Administrate
56
56
 
57
57
  def permitted_attributes
58
58
  form_attributes.map do |attr|
59
- attribute_types[attr].permitted_attribute(attr)
59
+ attribute_types[attr].permitted_attribute(
60
+ attr,
61
+ resource_class: self.class.model,
62
+ )
60
63
  end.uniq
61
64
  end
62
65
 
@@ -88,7 +91,7 @@ module Administrate
88
91
 
89
92
  def attribute_includes(attributes)
90
93
  attributes.map do |key|
91
- field = self.class::ATTRIBUTE_TYPES[key]
94
+ field = attribute_type_for(key)
92
95
 
93
96
  key if field.associative?
94
97
  end.compact
@@ -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,12 +3,32 @@ 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
34
  private
@@ -18,15 +38,39 @@ module Administrate
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