administrate 0.8.1 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +5 -5
  2. data/app/assets/javascripts/administrate/components/associative.js +5 -0
  3. data/app/assets/javascripts/administrate/components/date_time_picker.js +10 -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/base/_typography.scss +1 -1
  7. data/app/assets/stylesheets/administrate/components/_attributes.scss +4 -3
  8. data/app/assets/stylesheets/administrate/components/_buttons.scss +11 -0
  9. data/app/assets/stylesheets/administrate/components/_cells.scss +3 -5
  10. data/app/assets/stylesheets/administrate/components/_field-unit.scss +17 -4
  11. data/app/assets/stylesheets/administrate/components/_flashes.scss +0 -8
  12. data/app/assets/stylesheets/administrate/components/_main-content.scss +1 -0
  13. data/app/assets/stylesheets/administrate/components/_navigation.scss +2 -3
  14. data/app/assets/stylesheets/administrate/library/_variables.scss +10 -8
  15. data/app/assets/stylesheets/docs.scss +1 -0
  16. data/app/controllers/administrate/application_controller.rb +95 -21
  17. data/app/controllers/concerns/administrate/punditize.rb +36 -0
  18. data/app/helpers/administrate/application_helper.rb +51 -14
  19. data/app/views/administrate/application/_collection.html.erb +32 -33
  20. data/app/views/administrate/application/_collection_header_actions.html.erb +4 -0
  21. data/app/views/administrate/application/_collection_item_actions.html.erb +17 -0
  22. data/app/views/administrate/application/_flashes.html.erb +2 -1
  23. data/app/views/administrate/application/_form.html.erb +7 -4
  24. data/app/views/administrate/application/{_icons.erb → _icons.html.erb} +1 -1
  25. data/app/views/administrate/application/_index_header.html.erb +28 -0
  26. data/app/views/administrate/application/_navigation.html.erb +5 -3
  27. data/app/views/administrate/application/edit.html.erb +3 -3
  28. data/app/views/administrate/application/index.html.erb +11 -26
  29. data/app/views/administrate/application/new.html.erb +6 -1
  30. data/app/views/administrate/application/show.html.erb +5 -5
  31. data/app/views/fields/belongs_to/_form.html.erb +3 -3
  32. data/app/views/fields/belongs_to/_index.html.erb +1 -1
  33. data/app/views/fields/belongs_to/_show.html.erb +1 -1
  34. data/app/views/fields/date/_form.html.erb +24 -0
  35. data/app/views/fields/date/_index.html.erb +21 -0
  36. data/app/views/fields/date/_show.html.erb +21 -0
  37. data/app/views/fields/date_time/_form.html.erb +1 -1
  38. data/app/views/fields/date_time/_index.html.erb +1 -1
  39. data/app/views/fields/has_many/_form.html.erb +2 -2
  40. data/app/views/fields/has_many/_index.html.erb +1 -1
  41. data/app/views/fields/has_many/_show.html.erb +8 -5
  42. data/app/views/fields/has_one/_form.html.erb +1 -1
  43. data/app/views/fields/has_one/_index.html.erb +1 -1
  44. data/app/views/fields/has_one/_show.html.erb +4 -4
  45. data/app/views/fields/number/_form.html.erb +1 -1
  46. data/app/views/fields/password/_form.html.erb +23 -0
  47. data/app/views/fields/password/_index.html.erb +18 -0
  48. data/app/views/fields/password/_show.html.erb +18 -0
  49. data/app/views/fields/polymorphic/_form.html.erb +11 -9
  50. data/app/views/fields/polymorphic/_show.html.erb +8 -4
  51. data/app/views/fields/select/_form.html.erb +24 -10
  52. data/app/views/fields/string/_show.html.erb +2 -2
  53. data/app/views/fields/text/_show.html.erb +2 -3
  54. data/app/views/fields/time/_form.html.erb +23 -0
  55. data/app/views/fields/time/_index.html.erb +19 -0
  56. data/app/views/fields/time/_show.html.erb +19 -0
  57. data/app/views/fields/url/_form.html.erb +23 -0
  58. data/app/views/fields/url/_index.html.erb +20 -0
  59. data/app/views/fields/url/_show.html.erb +20 -0
  60. data/app/views/layouts/administrate/application.html.erb +2 -1
  61. data/config/locales/administrate.ar.yml +8 -6
  62. data/config/locales/administrate.bs.yml +29 -0
  63. data/config/locales/administrate.ca.yml +30 -0
  64. data/config/locales/administrate.da.yml +8 -6
  65. data/config/locales/administrate.de.yml +10 -8
  66. data/config/locales/administrate.en.yml +8 -6
  67. data/config/locales/administrate.es.yml +8 -6
  68. data/config/locales/administrate.fi.yml +30 -0
  69. data/config/locales/administrate.fr.yml +9 -7
  70. data/config/locales/administrate.id.yml +30 -0
  71. data/config/locales/administrate.it.yml +8 -6
  72. data/config/locales/administrate.ja.yml +8 -6
  73. data/config/locales/administrate.ko.yml +13 -11
  74. data/config/locales/administrate.nl.yml +12 -10
  75. data/config/locales/administrate.pl.yml +8 -6
  76. data/config/locales/administrate.pt-BR.yml +8 -6
  77. data/config/locales/administrate.pt.yml +8 -6
  78. data/config/locales/administrate.ru.yml +8 -6
  79. data/config/locales/administrate.sq.yml +30 -0
  80. data/config/locales/administrate.sv.yml +8 -6
  81. data/config/locales/administrate.tr.yml +30 -0
  82. data/config/locales/administrate.uk.yml +8 -6
  83. data/config/locales/administrate.vi.yml +8 -6
  84. data/config/locales/administrate.zh-CN.yml +8 -6
  85. data/config/locales/administrate.zh-TW.yml +10 -8
  86. data/config/unicorn.rb +8 -13
  87. data/docs/adding_controllers_without_related_model.md +52 -0
  88. data/docs/adding_custom_field_types.md +3 -1
  89. data/docs/authentication.md +3 -1
  90. data/docs/authorization.md +71 -0
  91. data/docs/customizing_attribute_partials.md +24 -2
  92. data/docs/customizing_controller_actions.md +50 -2
  93. data/docs/customizing_dashboards.md +210 -9
  94. data/docs/customizing_page_views.md +23 -5
  95. data/docs/extending_administrate.md +27 -0
  96. data/docs/getting_started.md +89 -15
  97. data/docs/guides/hiding_dashboards_from_sidebar.md +19 -0
  98. data/docs/guides.md +5 -0
  99. data/docs/rails_api.md +45 -0
  100. data/lib/administrate/base_dashboard.rb +53 -11
  101. data/lib/administrate/custom_dashboard.rb +15 -0
  102. data/lib/administrate/engine.rb +8 -1
  103. data/lib/administrate/field/associative.rb +55 -7
  104. data/lib/administrate/field/base.rb +35 -9
  105. data/lib/administrate/field/belongs_to.rb +18 -5
  106. data/lib/administrate/field/date.rb +20 -0
  107. data/lib/administrate/field/date_time.rb +13 -2
  108. data/lib/administrate/field/deferred.rb +29 -5
  109. data/lib/administrate/field/has_many.rb +32 -12
  110. data/lib/administrate/field/has_one.rb +39 -11
  111. data/lib/administrate/field/number.rb +19 -2
  112. data/lib/administrate/field/password.rb +25 -0
  113. data/lib/administrate/field/polymorphic.rb +42 -4
  114. data/lib/administrate/field/select.rb +10 -1
  115. data/lib/administrate/field/time.rb +19 -0
  116. data/lib/administrate/field/url.rb +21 -0
  117. data/lib/administrate/namespace.rb +6 -2
  118. data/lib/administrate/order.rb +52 -7
  119. data/lib/administrate/page/base.rb +9 -3
  120. data/lib/administrate/page/collection.rb +5 -1
  121. data/lib/administrate/page/form.rb +10 -3
  122. data/lib/administrate/resource_resolver.rb +4 -4
  123. data/lib/administrate/search.rb +138 -16
  124. data/lib/administrate/version.rb +1 -1
  125. data/lib/administrate/view_generator.rb +9 -3
  126. data/lib/administrate.rb +19 -0
  127. data/lib/generators/administrate/dashboard/USAGE +1 -1
  128. data/lib/generators/administrate/dashboard/dashboard_generator.rb +29 -17
  129. data/lib/generators/administrate/dashboard/templates/controller.rb.erb +35 -10
  130. data/lib/generators/administrate/dashboard/templates/dashboard.rb.erb +18 -6
  131. data/lib/generators/administrate/install/install_generator.rb +50 -7
  132. data/lib/generators/administrate/install/templates/{application_controller.rb → application_controller.rb.erb} +4 -4
  133. data/lib/generators/administrate/routes/routes_generator.rb +26 -26
  134. data/lib/generators/administrate/routes/templates/routes.rb.erb +1 -1
  135. data/lib/generators/administrate/views/field_generator.rb +19 -5
  136. data/lib/generators/administrate/views/layout_generator.rb +1 -0
  137. data/lib/generators/administrate/views/views_generator.rb +5 -4
  138. metadata +52 -53
  139. data/app/assets/javascripts/administrate/components/has_many_form.js +0 -3
  140. data/config/secrets.yml +0 -14
@@ -2,11 +2,49 @@ require_relative "associative"
2
2
 
3
3
  module Administrate
4
4
  module Field
5
- class Polymorphic < Associative
6
- protected
5
+ class Polymorphic < BelongsTo
6
+ def self.permitted_attribute(attr, _options = {})
7
+ { attr => %i{type value} }
8
+ end
9
+
10
+ def associated_resource_grouped_options
11
+ classes.map do |klass|
12
+ [klass.to_s, candidate_resources_for(klass).map do |resource|
13
+ [display_candidate_resource(resource), resource.to_global_id]
14
+ end]
15
+ end
16
+ end
17
+
18
+ def permitted_attribute
19
+ { attribute => %i{type value} }
20
+ end
21
+
22
+ def selected_global_id
23
+ data ? data.to_global_id : nil
24
+ end
25
+
26
+ private
27
+
28
+ def associated_dashboard(klass = data.class)
29
+ "#{klass.name}Dashboard".constantize.new
30
+ end
31
+
32
+ def classes
33
+ options.fetch(:classes, [])
34
+ end
35
+
36
+ private
37
+
38
+ def order
39
+ @_order ||= options.delete(:order)
40
+ end
41
+
42
+ def candidate_resources_for(klass)
43
+ order ? klass.order(order) : klass.all
44
+ end
7
45
 
8
- def associated_dashboard
9
- "#{data.class.name}Dashboard".constantize.new
46
+ def display_candidate_resource(resource)
47
+ associated_dashboard(resource.class).display_resource(resource)
10
48
  end
11
49
  end
12
50
  end
@@ -11,10 +11,19 @@ module Administrate
11
11
  collection
12
12
  end
13
13
 
14
+ def include_blank_option
15
+ options.fetch(:include_blank, false)
16
+ end
17
+
14
18
  private
15
19
 
16
20
  def collection
17
- @collection ||= options.fetch(:collection, [])
21
+ values = options.fetch(:collection, [])
22
+ if values.respond_to? :call
23
+ return values.arity.positive? ? values.call(self) : values.call
24
+ end
25
+
26
+ @collection ||= values
18
27
  end
19
28
  end
20
29
  end
@@ -0,0 +1,19 @@
1
+ require_relative "base"
2
+
3
+ module Administrate
4
+ module Field
5
+ class Time < Base
6
+ def time
7
+ return I18n.localize(data, format: format) if options[:format]
8
+
9
+ data.strftime("%I:%M%p")
10
+ end
11
+
12
+ private
13
+
14
+ def format
15
+ options[:format]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "base"
2
+
3
+ module Administrate
4
+ module Field
5
+ class Url < Field::Base
6
+ def self.searchable?
7
+ true
8
+ end
9
+
10
+ def truncate
11
+ data.to_s[0...truncation_length]
12
+ end
13
+
14
+ private
15
+
16
+ def truncation_length
17
+ options.fetch(:truncate, 50)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,7 +1,7 @@
1
1
  module Administrate
2
2
  class Namespace
3
3
  def initialize(namespace)
4
- @namespace = namespace
4
+ @namespace = namespace.to_sym
5
5
  end
6
6
 
7
7
  def resources
@@ -12,12 +12,16 @@ module Administrate
12
12
 
13
13
  def routes
14
14
  @routes ||= all_routes.select do |controller, _action|
15
- controller.starts_with?(namespace.to_s)
15
+ controller.starts_with?("#{namespace}/")
16
16
  end.map do |controller, action|
17
17
  [controller.gsub(/^#{namespace}\//, ""), action]
18
18
  end
19
19
  end
20
20
 
21
+ def resources_with_index_route
22
+ routes.select { |_resource, route| route == "index" }.map(&:first).uniq
23
+ end
24
+
21
25
  private
22
26
 
23
27
  attr_reader :namespace
@@ -2,15 +2,19 @@ module Administrate
2
2
  class Order
3
3
  def initialize(attribute = nil, direction = nil)
4
4
  @attribute = attribute
5
- @direction = direction || :asc
5
+ @direction = sanitize_direction(direction)
6
6
  end
7
7
 
8
8
  def apply(relation)
9
- if relation.columns_hash.keys.include?(attribute.to_s)
10
- relation.order("#{attribute} #{direction}")
11
- else
12
- relation
13
- end
9
+ return order_by_association(relation) unless
10
+ reflect_association(relation).nil?
11
+
12
+ order = "#{relation.table_name}.#{attribute} #{direction}"
13
+
14
+ return relation.reorder(Arel.sql(order)) if
15
+ relation.columns_hash.keys.include?(attribute.to_s)
16
+
17
+ relation
14
18
  end
15
19
 
16
20
  def ordered_by?(attr)
@@ -30,6 +34,10 @@ module Administrate
30
34
 
31
35
  attr_reader :attribute
32
36
 
37
+ def sanitize_direction(direction)
38
+ %w[asc desc].include?(direction.to_s) ? direction.to_sym : :asc
39
+ end
40
+
33
41
  def reversed_direction_param_for(attr)
34
42
  if ordered_by?(attr)
35
43
  opposite_direction
@@ -39,7 +47,44 @@ module Administrate
39
47
  end
40
48
 
41
49
  def opposite_direction
42
- direction.to_sym == :asc ? :desc : :asc
50
+ direction == :asc ? :desc : :asc
51
+ end
52
+
53
+ def order_by_association(relation)
54
+ return order_by_count(relation) if has_many_attribute?(relation)
55
+
56
+ return order_by_id(relation) if belongs_to_attribute?(relation)
57
+
58
+ relation
59
+ end
60
+
61
+ def order_by_count(relation)
62
+ klass = reflect_association(relation).klass
63
+ query = "COUNT(#{klass.table_name}.#{klass.primary_key}) #{direction}"
64
+ relation.
65
+ left_joins(attribute.to_sym).
66
+ group(:id).
67
+ reorder(Arel.sql(query))
68
+ end
69
+
70
+ def order_by_id(relation)
71
+ relation.reorder("#{foreign_key(relation)} #{direction}")
72
+ end
73
+
74
+ def has_many_attribute?(relation)
75
+ reflect_association(relation).macro == :has_many
76
+ end
77
+
78
+ def belongs_to_attribute?(relation)
79
+ reflect_association(relation).macro == :belongs_to
80
+ end
81
+
82
+ def reflect_association(relation)
83
+ relation.klass.reflect_on_association(attribute.to_s)
84
+ end
85
+
86
+ def foreign_key(relation)
87
+ reflect_association(relation).foreign_key
43
88
  end
44
89
  end
45
90
  end
@@ -15,7 +15,15 @@ module Administrate
15
15
  @resource_path ||= resource_name.gsub("/", "_")
16
16
  end
17
17
 
18
- protected
18
+ def collection_includes
19
+ dashboard.try(:collection_includes) || []
20
+ end
21
+
22
+ def item_includes
23
+ dashboard.try(:item_includes) || []
24
+ end
25
+
26
+ private
19
27
 
20
28
  def attribute_field(dashboard, resource, attribute_name, page)
21
29
  value = get_attribute_value(resource, attribute_name)
@@ -25,8 +33,6 @@ module Administrate
25
33
 
26
34
  def get_attribute_value(resource, attribute_name)
27
35
  resource.public_send(attribute_name)
28
- rescue NameError
29
- nil
30
36
  end
31
37
 
32
38
  attr_reader :dashboard, :options
@@ -21,7 +21,11 @@ module Administrate
21
21
  ordered_by?(attr) && order.direction
22
22
  end
23
23
 
24
- delegate :ordered_by?, :order_params_for, to: :order
24
+ delegate :ordered_by?, to: :order
25
+
26
+ def order_params_for(attr, key: resource_name)
27
+ { key => order.order_params_for(attr) }
28
+ end
25
29
 
26
30
  private
27
31
 
@@ -10,8 +10,15 @@ module Administrate
10
10
 
11
11
  attr_reader :resource
12
12
 
13
- def attributes
14
- dashboard.form_attributes.map do |attribute|
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
+ dashboard.form_attributes(action).map do |attribute|
15
22
  attribute_field(dashboard, resource, attribute, :form)
16
23
  end
17
24
  end
@@ -20,7 +27,7 @@ module Administrate
20
27
  dashboard.display_resource(resource)
21
28
  end
22
29
 
23
- protected
30
+ private
24
31
 
25
32
  attr_reader :dashboard
26
33
  end
@@ -5,15 +5,15 @@ module Administrate
5
5
  end
6
6
 
7
7
  def dashboard_class
8
- Object.const_get(resource_class_name + "Dashboard")
8
+ ActiveSupport::Inflector.constantize("#{resource_class_name}Dashboard")
9
9
  end
10
10
 
11
11
  def namespace
12
- controller_path.split("/").first
12
+ controller_path.split("/").first.to_sym
13
13
  end
14
14
 
15
15
  def resource_class
16
- Object.const_get(resource_class_name)
16
+ ActiveSupport::Inflector.constantize(resource_class_name)
17
17
  end
18
18
 
19
19
  def resource_name
@@ -21,7 +21,7 @@ module Administrate
21
21
  end
22
22
 
23
23
  def resource_title
24
- model_path_parts.join(" ")
24
+ resource_class.model_name.human
25
25
  end
26
26
 
27
27
  private
@@ -3,45 +3,167 @@ require "active_support/core_ext/object/blank"
3
3
 
4
4
  module Administrate
5
5
  class Search
6
- def initialize(scoped_resource, dashboard_class, term)
7
- @dashboard_class = dashboard_class
6
+ class Query
7
+ attr_reader :filters, :valid_filters
8
+
9
+ def blank?
10
+ terms.blank? && filters.empty?
11
+ end
12
+
13
+ def initialize(original_query, valid_filters = nil)
14
+ @original_query = original_query
15
+ @valid_filters = valid_filters
16
+ @filters, @terms = parse_query(original_query)
17
+ end
18
+
19
+ def original
20
+ @original_query
21
+ end
22
+
23
+ def terms
24
+ @terms.join(" ")
25
+ end
26
+
27
+ def to_s
28
+ original
29
+ end
30
+
31
+ private
32
+
33
+ def filter?(word)
34
+ valid_filters&.any? { |filter| word.match?(/^#{filter}:\w*$/) }
35
+ end
36
+
37
+ def parse_query(query)
38
+ filters = []
39
+ terms = []
40
+ query.to_s.split.each do |word|
41
+ if filter?(word)
42
+ filters << word
43
+ else
44
+ terms << word
45
+ end
46
+ end
47
+ [filters, terms]
48
+ end
49
+ end
50
+
51
+ def initialize(scoped_resource, dashboard, term)
52
+ @dashboard = dashboard
8
53
  @scoped_resource = scoped_resource
9
- @term = term
54
+ @query = Query.new(term, valid_filters.keys)
10
55
  end
11
56
 
12
57
  def run
13
- if @term.blank?
58
+ if query.blank?
14
59
  @scoped_resource.all
15
60
  else
16
- @scoped_resource.where(query, *search_terms)
61
+ results = search_results(@scoped_resource)
62
+ results = filter_results(results)
63
+ results
17
64
  end
18
65
  end
19
66
 
20
67
  private
21
68
 
22
- def query
69
+ def apply_filter(filter, filter_param, resources)
70
+ return resources unless filter
71
+ if filter.parameters.size == 1
72
+ filter.call(resources)
73
+ else
74
+ filter.call(resources, filter_param)
75
+ end
76
+ end
77
+
78
+ def filter_results(resources)
79
+ query.filters.each do |filter_query|
80
+ filter_name, filter_param = filter_query.split(":")
81
+ filter = valid_filters[filter_name]
82
+ resources = apply_filter(filter, filter_param, resources)
83
+ end
84
+ resources
85
+ end
86
+
87
+ def query_template
23
88
  search_attributes.map do |attr|
24
- table_name = ActiveRecord::Base.connection.
25
- quote_table_name(@scoped_resource.table_name)
26
- attr_name = ActiveRecord::Base.connection.quote_column_name(attr)
27
- "lower(#{table_name}.#{attr_name}) LIKE ?"
89
+ table_name = query_table_name(attr)
90
+ searchable_fields(attr).map do |field|
91
+ column_name = column_to_query(field)
92
+ "LOWER(CAST(#{table_name}.#{column_name} AS CHAR(256))) LIKE ?"
93
+ end.join(" OR ")
28
94
  end.join(" OR ")
29
95
  end
30
96
 
31
- def search_terms
32
- ["%#{term.mb_chars.downcase}%"] * search_attributes.count
97
+ def searchable_fields(attr)
98
+ return [attr] unless association_search?(attr)
99
+
100
+ attribute_types[attr].searchable_fields
101
+ end
102
+
103
+ def query_values
104
+ fields_count = search_attributes.sum do |attr|
105
+ searchable_fields(attr).count
106
+ end
107
+ ["%#{term.mb_chars.downcase}%"] * fields_count
33
108
  end
34
109
 
35
110
  def search_attributes
36
- attribute_types.keys.select do |attribute|
37
- attribute_types[attribute].searchable?
111
+ @dashboard.search_attributes
112
+ end
113
+
114
+ def search_results(resources)
115
+ resources.
116
+ left_joins(tables_to_join).
117
+ where(query_template, *query_values)
118
+ end
119
+
120
+ def valid_filters
121
+ if @dashboard.class.const_defined?(:COLLECTION_FILTERS)
122
+ @dashboard.class.const_get(:COLLECTION_FILTERS).stringify_keys
123
+ else
124
+ {}
38
125
  end
39
126
  end
40
127
 
41
128
  def attribute_types
42
- @dashboard_class::ATTRIBUTE_TYPES
129
+ @dashboard.class.const_get(:ATTRIBUTE_TYPES)
130
+ end
131
+
132
+ def query_table_name(attr)
133
+ if association_search?(attr)
134
+ provided_class_name = attribute_types[attr].options[:class_name]
135
+ unquoted_table_name =
136
+ if provided_class_name
137
+ Administrate.warn_of_deprecated_option(:class_name)
138
+ provided_class_name.constantize.table_name
139
+ else
140
+ @scoped_resource.reflect_on_association(attr).klass.table_name
141
+ end
142
+ ActiveRecord::Base.connection.quote_table_name(unquoted_table_name)
143
+ else
144
+ ActiveRecord::Base.connection.
145
+ quote_table_name(@scoped_resource.table_name)
146
+ end
147
+ end
148
+
149
+ def column_to_query(attr)
150
+ ActiveRecord::Base.connection.quote_column_name(attr)
151
+ end
152
+
153
+ def tables_to_join
154
+ attribute_types.keys.select do |attribute|
155
+ attribute_types[attribute].searchable? && association_search?(attribute)
156
+ end
157
+ end
158
+
159
+ def association_search?(attribute)
160
+ attribute_types[attribute].associative?
161
+ end
162
+
163
+ def term
164
+ query.terms
43
165
  end
44
166
 
45
- attr_reader :resolver, :term
167
+ attr_reader :resolver, :query
46
168
  end
47
169
  end
@@ -1,3 +1,3 @@
1
1
  module Administrate
2
- VERSION = "0.8.1".freeze
2
+ VERSION = "0.17.0".freeze
3
3
  end
@@ -1,11 +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
7
-
8
- private
8
+ class_option :namespace, type: :string, default: :admin
9
9
 
10
10
  def self.template_source_path
11
11
  File.expand_path(
@@ -14,12 +14,18 @@ module Administrate
14
14
  )
15
15
  end
16
16
 
17
+ private
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/admin/#{resource_path}/#{template_file}",
28
+ "app/views/#{namespace}/#{resource_path}/#{template_file}",
23
29
  )
24
30
  end
25
31
 
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
@@ -3,7 +3,7 @@ Description:
3
3
  pulling the attributes from database columns.
4
4
 
5
5
  Example:
6
- rails generate administrate:dashboard FooBar
6
+ rails generate administrate:dashboard FooBar [--namespace admin]
7
7
 
8
8
  This will create:
9
9
  app/dashboards/foo_bar_dashboard.rb
@@ -5,18 +5,21 @@ module Administrate
5
5
  class DashboardGenerator < Rails::Generators::NamedBase
6
6
  ATTRIBUTE_TYPE_MAPPING = {
7
7
  boolean: "Field::Boolean",
8
- date: "Field::DateTime",
8
+ date: "Field::Date",
9
9
  datetime: "Field::DateTime",
10
- enum: "Field::String",
10
+ enum: "Field::Select",
11
11
  float: "Field::Number",
12
12
  integer: "Field::Number",
13
- time: "Field::DateTime",
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 = {
19
- enum: { searchable: false },
20
+ # procs must be defined in one line!
21
+ enum: { searchable: false,
22
+ collection: ->(field) { field.resource.class.send(field.attribute.to_s.pluralize).keys } },
20
23
  float: { decimals: 2 },
21
24
  }
22
25
 
@@ -24,6 +27,8 @@ module Administrate
24
27
  COLLECTION_ATTRIBUTE_LIMIT = 4
25
28
  READ_ONLY_ATTRIBUTES = %w[id created_at updated_at]
26
29
 
30
+ class_option :namespace, type: :string, default: :admin
31
+
27
32
  source_root File.expand_path("../templates", __FILE__)
28
33
 
29
34
  def create_dashboard_definition
@@ -35,7 +40,7 @@ module Administrate
35
40
 
36
41
  def create_resource_controller
37
42
  destination = Rails.root.join(
38
- "app/controllers/admin/#{file_name.pluralize}_controller.rb",
43
+ "app/controllers/#{namespace}/#{file_name.pluralize}_controller.rb",
39
44
  )
40
45
 
41
46
  template("controller.rb.erb", destination)
@@ -43,8 +48,14 @@ module Administrate
43
48
 
44
49
  private
45
50
 
51
+ def namespace
52
+ options[:namespace]
53
+ end
54
+
46
55
  def attributes
47
- klass.reflections.keys + klass.attribute_names - redundant_attributes
56
+ klass.reflections.keys +
57
+ klass.columns.map(&:name) -
58
+ redundant_attributes
48
59
  end
49
60
 
50
61
  def form_attributes
@@ -99,11 +110,11 @@ module Administrate
99
110
  if relationship.has_one?
100
111
  "Field::HasOne"
101
112
  elsif relationship.collection?
102
- "Field::HasMany" + relationship_options_string(relationship)
113
+ "Field::HasMany"
103
114
  elsif relationship.polymorphic?
104
115
  "Field::Polymorphic"
105
116
  else
106
- "Field::BelongsTo" + relationship_options_string(relationship)
117
+ "Field::BelongsTo"
107
118
  end
108
119
  end
109
120
 
@@ -111,14 +122,6 @@ module Administrate
111
122
  @klass ||= Object.const_get(class_name)
112
123
  end
113
124
 
114
- def relationship_options_string(relationship)
115
- if relationship.class_name != relationship.name.to_s.classify
116
- options_string(class_name: relationship.class_name)
117
- else
118
- ""
119
- end
120
- end
121
-
122
125
  def options_string(options)
123
126
  if options.any?
124
127
  ".with_options(#{inspect_hash_as_ruby(options)})"
@@ -128,7 +131,16 @@ module Administrate
128
131
  end
129
132
 
130
133
  def inspect_hash_as_ruby(hash)
131
- hash.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
134
+ hash.map do |key, value|
135
+ v_str = value.respond_to?(:call) ? proc_string(value) : value.inspect
136
+ "#{key}: #{v_str}"
137
+ end.join(", ")
138
+ end
139
+
140
+ def proc_string(value)
141
+ source = value.source_location
142
+ proc_string = IO.readlines(source.first)[source.second - 1]
143
+ proc_string[/->[^}]*} | (lambda|proc).*end/x]
132
144
  end
133
145
  end
134
146
  end