administrate 0.14.0 → 0.15.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/associative.js +1 -0
- data/app/assets/stylesheets/administrate/components/_attributes.scss +3 -2
- data/app/assets/stylesheets/administrate/components/_field-unit.scss +4 -0
- data/app/assets/stylesheets/administrate/components/_main-content.scss +1 -0
- data/app/controllers/administrate/application_controller.rb +11 -11
- data/app/helpers/administrate/application_helper.rb +10 -23
- data/app/views/administrate/application/_collection.html.erb +1 -1
- data/app/views/administrate/application/_form.html.erb +1 -1
- data/app/views/administrate/application/index.html.erb +2 -2
- data/app/views/administrate/application/show.html.erb +1 -1
- data/app/views/fields/belongs_to/_form.html.erb +3 -3
- data/app/views/fields/has_one/_index.html.erb +1 -1
- data/app/views/fields/has_one/_show.html.erb +4 -4
- data/app/views/fields/number/_form.html.erb +1 -1
- data/app/views/fields/polymorphic/_show.html.erb +1 -1
- data/app/views/fields/select/_form.html.erb +2 -2
- data/app/views/fields/time/_index.html.erb +3 -1
- data/app/views/fields/time/_show.html.erb +3 -1
- data/app/views/layouts/administrate/application.html.erb +1 -0
- data/config/locales/administrate.fi.yml +30 -0
- data/config/locales/administrate.fr.yml +2 -2
- data/config/locales/administrate.nl.yml +4 -4
- data/config/locales/administrate.pt-BR.yml +2 -2
- data/config/locales/administrate.pt.yml +3 -3
- data/config/locales/administrate.tr.yml +30 -0
- data/config/unicorn.rb +8 -13
- data/docs/adding_controllers_without_related_model.md +18 -0
- data/docs/customizing_dashboards.md +32 -16
- data/docs/extending_administrate.md +27 -0
- data/docs/getting_started.md +27 -5
- data/docs/guides.md +5 -0
- data/docs/guides/hiding_dashboards_from_sidebar.md +19 -0
- data/lib/administrate.rb +19 -0
- data/lib/administrate/base_dashboard.rb +5 -2
- data/lib/administrate/engine.rb +7 -0
- data/lib/administrate/field/associative.rb +48 -4
- data/lib/administrate/field/base.rb +26 -0
- data/lib/administrate/field/belongs_to.rb +13 -3
- data/lib/administrate/field/deferred.rb +7 -3
- data/lib/administrate/field/has_many.rb +15 -2
- data/lib/administrate/field/has_one.rb +28 -8
- data/lib/administrate/field/number.rb +19 -2
- data/lib/administrate/field/polymorphic.rb +1 -1
- data/lib/administrate/order.rb +3 -1
- data/lib/administrate/resource_resolver.rb +1 -1
- data/lib/administrate/search.rb +11 -8
- data/lib/administrate/version.rb +1 -1
- data/lib/administrate/view_generator.rb +7 -1
- data/lib/generators/administrate/dashboard/dashboard_generator.rb +3 -10
- data/lib/generators/administrate/dashboard/templates/dashboard.rb.erb +3 -3
- data/lib/generators/administrate/install/install_generator.rb +37 -1
- data/lib/generators/administrate/routes/routes_generator.rb +3 -13
- data/lib/generators/administrate/views/views_generator.rb +5 -4
- metadata +15 -25
- data/docs/contributing.md +0 -1
@@ -48,6 +48,32 @@ module Administrate
|
|
48
48
|
"/fields/#{self.class.field_type}/#{page}"
|
49
49
|
end
|
50
50
|
|
51
|
+
def required?
|
52
|
+
return false unless resource.class.respond_to?(:validators_on)
|
53
|
+
|
54
|
+
resource.class.validators_on(attribute).any? do |v|
|
55
|
+
next false unless v.class == ActiveRecord::Validations::PresenceValidator
|
56
|
+
|
57
|
+
options = v.options
|
58
|
+
next false if options.include?(:if)
|
59
|
+
next false if options.include?(:unless)
|
60
|
+
|
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
|
75
|
+
end
|
76
|
+
|
51
77
|
attr_reader :attribute, :data, :options, :page, :resource
|
52
78
|
end
|
53
79
|
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,
|
7
|
-
:
|
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
|
-
|
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
|
@@ -44,9 +44,13 @@ module Administrate
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
def permitted_attribute(attr,
|
48
|
-
options.
|
49
|
-
|
47
|
+
def permitted_attribute(attr, opts = {})
|
48
|
+
if options.key?(:foreign_key)
|
49
|
+
Administrate.warn_of_deprecated_option(:foreign_key)
|
50
|
+
options.fetch(:foreign_key)
|
51
|
+
else
|
52
|
+
deferred_class.permitted_attribute(attr, options.merge(opts))
|
53
|
+
end
|
50
54
|
end
|
51
55
|
|
52
56
|
delegate :html_class, to: :deferred_class
|
@@ -7,7 +7,17 @@ module Administrate
|
|
7
7
|
class HasMany < Associative
|
8
8
|
DEFAULT_LIMIT = 5
|
9
9
|
|
10
|
-
def self.permitted_attribute(attr, _options =
|
10
|
+
def self.permitted_attribute(attr, _options = {})
|
11
|
+
# This may seem arbitrary, and improvable by using reflection.
|
12
|
+
# Worry not: here we do exactly what Rails does. Regardless of the name
|
13
|
+
# of the foreign key, has_many associations use the suffix `_ids`
|
14
|
+
# for this.
|
15
|
+
#
|
16
|
+
# Eg: if the associated table and primary key are `countries.code`,
|
17
|
+
# you may expect `country_codes` as attribute here, but it will
|
18
|
+
# be `country_ids` instead.
|
19
|
+
#
|
20
|
+
# See https://github.com/rails/rails/blob/b30a23f53b52e59d31358f7b80385ee5c2ba3afe/activerecord/lib/active_record/associations/builder/collection_association.rb#L48
|
11
21
|
{ "#{attr.to_s.singularize}_ids".to_sym => [] }
|
12
22
|
end
|
13
23
|
|
@@ -36,7 +46,10 @@ module Administrate
|
|
36
46
|
end
|
37
47
|
|
38
48
|
def permitted_attribute
|
39
|
-
self.class.permitted_attribute(
|
49
|
+
self.class.permitted_attribute(
|
50
|
+
attribute,
|
51
|
+
resource_class: resource.class,
|
52
|
+
)
|
40
53
|
end
|
41
54
|
|
42
55
|
def resources(page = 1, order = self.order)
|
@@ -3,17 +3,26 @@ require_relative "associative"
|
|
3
3
|
module Administrate
|
4
4
|
module Field
|
5
5
|
class HasOne < Associative
|
6
|
-
def self.permitted_attribute(attr, options =
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
def self.permitted_attribute(attr, options = {})
|
7
|
+
resource_class = options[:resource_class]
|
8
|
+
final_associated_class_name =
|
9
|
+
if options.key?(:class_name)
|
10
|
+
Administrate.warn_of_deprecated_option(:class_name)
|
11
|
+
options.fetch(:class_name)
|
12
|
+
elsif resource_class
|
13
|
+
associated_class_name(resource_class, attr)
|
10
14
|
else
|
11
|
-
|
15
|
+
Administrate.warn_of_missing_resource_class
|
16
|
+
if options
|
17
|
+
attr.to_s.singularize.camelcase
|
18
|
+
else
|
19
|
+
attr
|
20
|
+
end
|
12
21
|
end
|
13
22
|
related_dashboard_attributes =
|
14
|
-
Administrate::ResourceResolver.
|
23
|
+
Administrate::ResourceResolver.
|
24
|
+
new("admin/#{final_associated_class_name}").
|
15
25
|
dashboard_class.new.permitted_attributes + [:id]
|
16
|
-
|
17
26
|
{ "#{attr}_attributes": related_dashboard_attributes }
|
18
27
|
end
|
19
28
|
|
@@ -24,11 +33,22 @@ module Administrate
|
|
24
33
|
)
|
25
34
|
end
|
26
35
|
|
36
|
+
def nested_show
|
37
|
+
@nested_show ||= Administrate::Page::Show.new(
|
38
|
+
resolver.dashboard_class.new,
|
39
|
+
data || resolver.resource_class.new,
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def linkable?
|
44
|
+
data.try(:persisted?)
|
45
|
+
end
|
46
|
+
|
27
47
|
private
|
28
48
|
|
29
49
|
def resolver
|
30
50
|
@resolver ||=
|
31
|
-
Administrate::ResourceResolver.new("admin/#{
|
51
|
+
Administrate::ResourceResolver.new("admin/#{associated_class.name}")
|
32
52
|
end
|
33
53
|
end
|
34
54
|
end
|
@@ -1,16 +1,19 @@
|
|
1
1
|
require_relative "base"
|
2
|
+
require "active_support/number_helper"
|
2
3
|
|
3
4
|
module Administrate
|
4
5
|
module Field
|
5
6
|
class Number < Field::Base
|
6
7
|
def to_s
|
7
|
-
data.nil? ? "-" : format_string % value
|
8
|
+
result = data.nil? ? "-" : format_string % value
|
9
|
+
result = format(result) if options[:format]
|
10
|
+
prefix + result + suffix
|
8
11
|
end
|
9
12
|
|
10
13
|
private
|
11
14
|
|
12
15
|
def format_string
|
13
|
-
|
16
|
+
"%.#{decimals}f"
|
14
17
|
end
|
15
18
|
|
16
19
|
def prefix
|
@@ -30,6 +33,20 @@ module Administrate
|
|
30
33
|
def value
|
31
34
|
data * options.fetch(:multiplier, 1)
|
32
35
|
end
|
36
|
+
|
37
|
+
def format(result)
|
38
|
+
formatter = options[:format][:formatter]
|
39
|
+
formatter_options = options[:format][:formatter_options].to_h
|
40
|
+
|
41
|
+
case formatter
|
42
|
+
when :number_to_delimited
|
43
|
+
ActiveSupport::NumberHelper.number_to_delimited(
|
44
|
+
result, **formatter_options
|
45
|
+
)
|
46
|
+
else
|
47
|
+
result
|
48
|
+
end
|
49
|
+
end
|
33
50
|
end
|
34
51
|
end
|
35
52
|
end
|
data/lib/administrate/order.rb
CHANGED
@@ -59,10 +59,12 @@ module Administrate
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def order_by_count(relation)
|
62
|
+
klass = reflect_association(relation).klass
|
63
|
+
query = "COUNT(#{klass.table_name}.#{klass.primary_key}) #{direction}"
|
62
64
|
relation.
|
63
65
|
left_joins(attribute.to_sym).
|
64
66
|
group(:id).
|
65
|
-
reorder(
|
67
|
+
reorder(Arel.sql(query))
|
66
68
|
end
|
67
69
|
|
68
70
|
def order_by_id(relation)
|
data/lib/administrate/search.rb
CHANGED
@@ -82,8 +82,8 @@ module Administrate
|
|
82
82
|
search_attributes.map do |attr|
|
83
83
|
table_name = query_table_name(attr)
|
84
84
|
searchable_fields(attr).map do |field|
|
85
|
-
|
86
|
-
"LOWER(CAST(#{table_name}.#{
|
85
|
+
column_name = column_to_query(field)
|
86
|
+
"LOWER(CAST(#{table_name}.#{column_name} AS CHAR(256))) LIKE ?"
|
87
87
|
end.join(" OR ")
|
88
88
|
end.join(" OR ")
|
89
89
|
end
|
@@ -109,7 +109,7 @@ module Administrate
|
|
109
109
|
|
110
110
|
def search_results(resources)
|
111
111
|
resources.
|
112
|
-
|
112
|
+
left_joins(tables_to_join).
|
113
113
|
where(query_template, *query_values)
|
114
114
|
end
|
115
115
|
|
@@ -128,11 +128,14 @@ module Administrate
|
|
128
128
|
def query_table_name(attr)
|
129
129
|
if association_search?(attr)
|
130
130
|
provided_class_name = attribute_types[attr].options[:class_name]
|
131
|
-
|
132
|
-
provided_class_name
|
133
|
-
|
134
|
-
|
135
|
-
|
131
|
+
unquoted_table_name =
|
132
|
+
if provided_class_name
|
133
|
+
Administrate.warn_of_deprecated_option(:class_name)
|
134
|
+
provided_class_name.constantize.table_name
|
135
|
+
else
|
136
|
+
@scoped_resource.reflect_on_association(attr).klass.table_name
|
137
|
+
end
|
138
|
+
ActiveRecord::Base.connection.quote_table_name(unquoted_table_name)
|
136
139
|
else
|
137
140
|
ActiveRecord::Base.connection.
|
138
141
|
quote_table_name(@scoped_resource.table_name)
|
data/lib/administrate/version.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require "rails/generators/base"
|
2
2
|
require "administrate/generator_helpers"
|
3
|
+
require "administrate/namespace"
|
3
4
|
|
4
5
|
module Administrate
|
5
6
|
class ViewGenerator < Rails::Generators::Base
|
6
7
|
include Administrate::GeneratorHelpers
|
8
|
+
class_option :namespace, type: :string, default: "admin"
|
7
9
|
|
8
10
|
def self.template_source_path
|
9
11
|
File.expand_path(
|
@@ -14,12 +16,16 @@ module Administrate
|
|
14
16
|
|
15
17
|
private
|
16
18
|
|
19
|
+
def namespace
|
20
|
+
options[:namespace]
|
21
|
+
end
|
22
|
+
|
17
23
|
def copy_resource_template(template_name)
|
18
24
|
template_file = "#{template_name}.html.erb"
|
19
25
|
|
20
26
|
copy_file(
|
21
27
|
template_file,
|
22
|
-
"app/views
|
28
|
+
"app/views/#{namespace}/#{resource_path}/#{template_file}",
|
23
29
|
)
|
24
30
|
end
|
25
31
|
|
@@ -13,6 +13,7 @@ module Administrate
|
|
13
13
|
time: "Field::Time",
|
14
14
|
text: "Field::Text",
|
15
15
|
string: "Field::String",
|
16
|
+
uuid: "Field::String",
|
16
17
|
}
|
17
18
|
|
18
19
|
ATTRIBUTE_OPTIONS_MAPPING = {
|
@@ -109,11 +110,11 @@ module Administrate
|
|
109
110
|
if relationship.has_one?
|
110
111
|
"Field::HasOne"
|
111
112
|
elsif relationship.collection?
|
112
|
-
"Field::HasMany"
|
113
|
+
"Field::HasMany"
|
113
114
|
elsif relationship.polymorphic?
|
114
115
|
"Field::Polymorphic"
|
115
116
|
else
|
116
|
-
"Field::BelongsTo"
|
117
|
+
"Field::BelongsTo"
|
117
118
|
end
|
118
119
|
end
|
119
120
|
|
@@ -121,14 +122,6 @@ module Administrate
|
|
121
122
|
@klass ||= Object.const_get(class_name)
|
122
123
|
end
|
123
124
|
|
124
|
-
def relationship_options_string(relationship)
|
125
|
-
if relationship.class_name != relationship.name.to_s.classify
|
126
|
-
options_string(class_name: relationship.class_name)
|
127
|
-
else
|
128
|
-
""
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
125
|
def options_string(options)
|
133
126
|
if options.any?
|
134
127
|
".with_options(#{inspect_hash_as_ruby(options)})"
|
@@ -21,7 +21,7 @@ class <%= class_name %>Dashboard < Administrate::BaseDashboard
|
|
21
21
|
COLLECTION_ATTRIBUTES = %i[
|
22
22
|
<%=
|
23
23
|
attributes.first(COLLECTION_ATTRIBUTE_LIMIT).map do |attr|
|
24
|
-
"
|
24
|
+
" #{attr}"
|
25
25
|
end.join("\n")
|
26
26
|
%>
|
27
27
|
].freeze
|
@@ -31,7 +31,7 @@ class <%= class_name %>Dashboard < Administrate::BaseDashboard
|
|
31
31
|
SHOW_PAGE_ATTRIBUTES = %i[
|
32
32
|
<%=
|
33
33
|
attributes.map do |attr|
|
34
|
-
"
|
34
|
+
" #{attr}"
|
35
35
|
end.join("\n")
|
36
36
|
%>
|
37
37
|
].freeze
|
@@ -42,7 +42,7 @@ class <%= class_name %>Dashboard < Administrate::BaseDashboard
|
|
42
42
|
FORM_ATTRIBUTES = %i[
|
43
43
|
<%=
|
44
44
|
form_attributes.map do |attr|
|
45
|
-
"
|
45
|
+
" #{attr}"
|
46
46
|
end.join("\n")
|
47
47
|
%>
|
48
48
|
].freeze
|
@@ -1,3 +1,9 @@
|
|
1
|
+
if defined?(Zeitwerk)
|
2
|
+
Zeitwerk::Loader.eager_load_all
|
3
|
+
else
|
4
|
+
Rails.application.eager_load!
|
5
|
+
end
|
6
|
+
|
1
7
|
require "rails/generators/base"
|
2
8
|
require "administrate/generator_helpers"
|
3
9
|
require "administrate/namespace"
|
@@ -13,7 +19,7 @@ module Administrate
|
|
13
19
|
def run_routes_generator
|
14
20
|
if dashboard_resources.none?
|
15
21
|
call_generator("administrate:routes", "--namespace", namespace)
|
16
|
-
|
22
|
+
Rails.application.reload_routes!
|
17
23
|
end
|
18
24
|
end
|
19
25
|
|
@@ -31,6 +37,12 @@ module Administrate
|
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
40
|
+
def model_check
|
41
|
+
if valid_dashboard_models.none?
|
42
|
+
puts "WARNING: Add models before installing Administrate."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
34
46
|
private
|
35
47
|
|
36
48
|
def namespace
|
@@ -44,6 +56,30 @@ module Administrate
|
|
44
56
|
def dashboard_resources
|
45
57
|
Administrate::Namespace.new(namespace).resources
|
46
58
|
end
|
59
|
+
|
60
|
+
def valid_dashboard_models
|
61
|
+
database_models - invalid_dashboard_models
|
62
|
+
end
|
63
|
+
|
64
|
+
def database_models
|
65
|
+
ActiveRecord::Base.descendants.reject(&:abstract_class?)
|
66
|
+
end
|
67
|
+
|
68
|
+
def invalid_dashboard_models
|
69
|
+
(models_without_tables + namespaced_models + unnamed_constants).uniq
|
70
|
+
end
|
71
|
+
|
72
|
+
def models_without_tables
|
73
|
+
database_models.reject(&:table_exists?)
|
74
|
+
end
|
75
|
+
|
76
|
+
def namespaced_models
|
77
|
+
database_models.select { |model| model.to_s.include?("::") }
|
78
|
+
end
|
79
|
+
|
80
|
+
def unnamed_constants
|
81
|
+
ActiveRecord::Base.descendants.reject { |d| d.name == d.to_s }
|
82
|
+
end
|
47
83
|
end
|
48
84
|
end
|
49
85
|
end
|