plutonium 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/app/assets/javascripts/turbo/index.js +1 -1
  4. data/app/views/application/_resource_header.html.erb +12 -12
  5. data/app/views/layouts/resource.html.erb +1 -0
  6. data/app/views/layouts/rodauth.html.erb +4 -4
  7. data/app/views/resource/_nav_user.html.erb +1 -1
  8. data/app/views/resource/index.rabl +1 -1
  9. data/brakeman.ignore +1 -1
  10. data/config/initializers/rabl.rb +2 -0
  11. data/css.manifest +1 -1
  12. data/js.manifest +2 -2
  13. data/lib/generators/pu/core/install/templates/config/initializers/plutonium.rb +0 -3
  14. data/lib/generators/pu/gen/pug/pug_generator.rb +6 -0
  15. data/lib/generators/pu/gen/pug/templates/pug.rb.tt +1 -1
  16. data/lib/generators/pu/pkg/app/templates/config/routes.rb.tt +3 -3
  17. data/lib/plutonium/config.rb +0 -11
  18. data/lib/plutonium/core/autodiscovery/input_discoverer.rb +1 -1
  19. data/lib/plutonium/core/autodiscovery/renderer_discoverer.rb +1 -1
  20. data/lib/plutonium/core/controllers/base.rb +13 -3
  21. data/lib/plutonium/core/controllers/queryable.rb +3 -1
  22. data/lib/plutonium/pkg/app.rb +6 -0
  23. data/lib/plutonium/railtie.rb +15 -0
  24. data/lib/plutonium/reloader.rb +99 -0
  25. data/lib/plutonium/resource/controller.rb +61 -22
  26. data/lib/plutonium/resource/policy.rb +56 -9
  27. data/lib/plutonium/resource/presenter.rb +44 -12
  28. data/lib/plutonium/resource/query_object.rb +186 -73
  29. data/lib/plutonium/resource/record.rb +213 -119
  30. data/lib/plutonium/rodauth/controller_methods.rb +7 -0
  31. data/lib/plutonium/version.rb +1 -1
  32. data/lib/plutonium.rb +50 -12
  33. data/package-lock.json +174 -0
  34. data/package.json +2 -0
  35. data/public/plutonium-assets/plutonium-app-6WILQCTT.js +39 -0
  36. data/public/plutonium-assets/plutonium-app-6WILQCTT.js.map +7 -0
  37. data/public/plutonium-assets/plutonium-logo-original.png +0 -0
  38. data/public/plutonium-assets/plutonium-logo-white.png +0 -0
  39. data/public/plutonium-assets/plutonium-logo.png +0 -0
  40. data/public/plutonium-assets/plutonium.2d4f0c333cd000051d3b.css +3424 -0
  41. data/public/plutonium-assets/plutonium.ico +0 -0
  42. metadata +10 -4
  43. data/lib/plutonium/reactor/core.rb +0 -78
  44. data/public/plutonium-assets/logo.png +0 -0
@@ -10,113 +10,135 @@ module Plutonium
10
10
  named_scope = :"associated_with_#{record.model_name.singular}"
11
11
  return send(named_scope, record) if respond_to?(named_scope)
12
12
 
13
- # TODO: add suppport for polymorphic associations
13
+ # TODO: add support for polymorphic associations
14
14
  # TODO: add logging
15
15
  # TODO: memoize this
16
16
 
17
- if (own_association = reflect_on_all_associations.find { |assoc| assoc.klass.name == record.class.name })
18
- case own_association.macro
19
- when :has_one
20
- joins(own_association.name).where({
21
- own_association.name => {
22
- record.class.primary_key => record.id
23
- }
24
- })
25
- when :belongs_to
26
- where(own_association.name => record)
27
- when :has_many
28
- joins(own_association.name).where(own_association.klass.table_name => record)
29
- else
30
- raise NotImplementedError, "associated_with->##{own_association.macro}"
31
- end
32
- elsif (record_association = record.class.reflect_on_all_associations.find { |assoc| assoc.klass.name == klass.name })
17
+ own_association = klass.find_association_to_record(record)
18
+ if own_association
19
+ return klass.query_based_on_association(own_association, record)
20
+ end
21
+
22
+ record_association = klass.find_association_to_self(record)
23
+ if record_association
33
24
  # TODO: add a warning here about a potentially poor performing query
34
- where(id: record.send(record_association.name))
35
- else
36
- raise "Could not resolve the association between '#{klass.name}' and '#{record.class.name}'\n\n" \
37
- "Define\n" \
38
- " 1. the associations between the models\n" \
39
- " 2. a named scope on #{klass.name} e.g.\n\n" \
40
- "scope :#{named_scope}, ->(#{record.model_name.singular}) { do_something_here }"
25
+ return where(id: record.send(record_association.name))
41
26
  end
27
+
28
+ klass.raise_association_error(record, named_scope)
42
29
  end
43
30
  end
44
31
 
45
32
  class_methods do
33
+ # Returns the resource field names
34
+ # @return [Array<Symbol>]
46
35
  def resource_field_names
47
- @resource_field_names ||= belongs_to_association_field_names +
48
- has_one_attached_field_names + has_one_association_field_names +
49
- has_many_attached_field_names + has_many_association_field_names +
50
- content_column_field_names
36
+ return @resource_field_names if defined?(@resource_field_names) && !Rails.env.local?
37
+
38
+ @resource_field_names = gather_resource_field_names
51
39
  end
52
40
 
41
+ # Overrides belongs_to to add support for polymorphic associations
42
+ # @param [Symbol] name The name of the association
43
+ # @param [Proc] scope The scope for the association
44
+ # @param [Hash] options The options for the association
53
45
  def belongs_to(name, scope = nil, **options)
54
46
  super(name, scope, **options)
55
47
 
56
- if options[:polymorphic]
57
- mod = Module.new
58
- mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
59
- extend ActiveSupport::Concern
48
+ return unless options[:polymorphic]
60
49
 
61
- def #{name}_sgid
62
- #{name}&.to_signed_global_id
63
- end
50
+ mod = Module.new
51
+ mod.module_eval <<-RUBY, __FILE__, __LINE__ + 1
52
+ extend ActiveSupport::Concern
64
53
 
65
- def #{name}_sgid=(sgid)
66
- self.#{name} = GlobalID::Locator.locate_signed(sgid)
67
- end
54
+ def #{name}_sgid
55
+ #{name}&.to_signed_global_id
56
+ end
68
57
 
69
- define_singleton_method(:to_s) { "Plutonium::Polymormorphic::BelongsTo(:#{name})" }
70
- define_singleton_method(:inspect) { "Plutonium::Polymormorphic::BelongsTo(:#{name})" }
71
- RUBY
72
- include mod
73
- end
58
+ def #{name}_sgid=(sgid)
59
+ self.#{name} = GlobalID::Locator.locate_signed(sgid)
60
+ end
61
+
62
+ define_singleton_method(:to_s) { "Plutonium::Polymorphic::BelongsTo(:#{name})" }
63
+ define_singleton_method(:inspect) { "Plutonium::Polymorphic::BelongsTo(:#{name})" }
64
+ RUBY
65
+ include mod
74
66
  end
75
67
 
68
+ # Returns the names of belongs_to associations
69
+ # @return [Array<Symbol>]
76
70
  def belongs_to_association_field_names
77
- @belongs_to_association_field_names ||= reflect_on_all_associations(:belongs_to).map(&:name)
71
+ return @belongs_to_association_field_names if defined?(@belongs_to_association_field_names) && !Rails.env.local?
72
+
73
+ @belongs_to_association_field_names = reflect_on_all_associations(:belongs_to).map(&:name)
78
74
  end
79
75
 
76
+ # Returns the names of has_one associations
77
+ # @return [Array<Symbol>]
80
78
  def has_one_association_field_names
81
- @has_one_association_field_names ||= reflect_on_all_associations(:has_one)
82
- .map { |assoc| /_attachment$|_blob$/.match?(assoc.name) ? nil : assoc.name }
79
+ return @has_one_association_field_names if defined?(@has_one_association_field_names) && !Rails.env.local?
80
+
81
+ @has_one_association_field_names = reflect_on_all_associations(:has_one)
82
+ .map { |assoc| (!/_attachment$|_blob$/.match?(assoc.name)) ? assoc.name : nil }
83
83
  .compact
84
84
  end
85
85
 
86
+ # Returns the names of has_many associations
87
+ # @return [Array<Symbol>]
86
88
  def has_many_association_field_names
87
- @has_many_association_field_names ||= reflect_on_all_associations(:has_many)
88
- .map { |assoc| /_attachments$|_blobs$/.match?(assoc.name) ? nil : assoc.name }
89
+ return @has_many_association_field_names if defined?(@has_many_association_field_names) && !Rails.env.local?
90
+
91
+ @has_many_association_field_names = reflect_on_all_associations(:has_many)
92
+ .map { |assoc| (!/_attachments$|_blobs$/.match?(assoc.name)) ? assoc.name : nil }
89
93
  .compact
90
94
  end
91
95
 
96
+ # Returns the names of has_one attached associations
97
+ # @return [Array<Symbol>]
92
98
  def has_one_attached_field_names
93
- @has_one_attached_field_names ||= if respond_to?(:reflect_on_all_attachments)
99
+ return @has_one_attached_field_names if defined?(@has_one_attached_field_names) && !Rails.env.local?
100
+
101
+ @has_one_attached_field_names = if respond_to?(:reflect_on_all_attachments)
94
102
  reflect_on_all_attachments
95
- .map { |a| (a.macro == :has_one_attached) ? a.name : nil }
96
- .compact
103
+ .select { |a| a.macro == :has_one_attached }
104
+ .map(&:name)
97
105
  else
98
106
  []
99
107
  end
100
108
  end
101
109
 
110
+ # Returns the names of has_many attached associations
111
+ # @return [Array<Symbol>]
102
112
  def has_many_attached_field_names
103
- @has_many_attached_field_names ||= if respond_to?(:reflect_on_all_attachments)
113
+ return @has_many_attached_field_names if defined?(@has_many_attached_field_names) && !Rails.env.local?
114
+
115
+ @has_many_attached_field_names = if respond_to?(:reflect_on_all_attachments)
104
116
  reflect_on_all_attachments
105
- .map { |a| (a.macro == :has_many_attached) ? a.name : nil }
106
- .compact
117
+ .select { |a| a.macro == :has_many_attached }
118
+ .map(&:name)
107
119
  else
108
120
  []
109
121
  end
110
122
  end
111
123
 
124
+ # Returns the names of content columns
125
+ # @return [Array<Symbol>]
112
126
  def content_column_field_names
113
- @content_column_field_names ||= content_columns.map { |col| col.name.to_sym }
127
+ return @content_column_field_names if defined?(@content_column_field_names) && !Rails.env.local?
128
+
129
+ @content_column_field_names = content_columns.map { |col| col.name.to_sym }
114
130
  end
115
131
 
132
+ # Returns the routes for has_many associations
133
+ # @return [Array<Symbol>]
116
134
  def has_many_association_routes
117
- @has_many_association_routes ||= reflect_on_all_associations(:has_many).map { |assoc| assoc.klass.model_name.plural }
135
+ return @has_many_association_routes if defined?(@has_many_association_routes) && !Rails.env.local?
136
+
137
+ @has_many_association_routes = reflect_on_all_associations(:has_many).map { |assoc| assoc.klass.model_name.plural }
118
138
  end
119
139
 
140
+ # Returns all nested attributes options
141
+ # @return [Hash]
120
142
  def all_nested_attributes_options
121
143
  unless Rails.env.local?
122
144
  return @all_nested_attributes_options if defined?(@all_nested_attributes_options)
@@ -125,98 +147,155 @@ module Plutonium
125
147
  @all_nested_attributes_options = reflect_on_all_associations.map do |association|
126
148
  setter_method = "#{association.name}_attributes="
127
149
  if method_defined?(setter_method)
128
- [association.name, {
129
- **nested_attributes_options[association.name],
150
+ [association.name, nested_attributes_options[association.name].merge(
130
151
  macro: association.macro,
131
152
  class: association.polymorphic? ? nil : association.klass
132
- }]
153
+ )]
133
154
  end
134
155
  end.compact.to_h
135
156
  end
136
157
 
137
- #
138
158
  # Returns the strong parameters definition for the given attribute names
139
- #
140
- # @param [Array] *attributes Attribute names
141
- #
142
- # @return [Array] A strong parameters compatible array e.g.
143
- # [:title, :body, {:images=>[]}, {:docs=>[]}]
144
- #
159
+ # @param [Array<Symbol>] *attributes Attribute names
160
+ # @return [Array<Symbol, Hash>] A strong parameters compatible array
145
161
  def strong_parameters_for(*attributes)
146
- # attributes that are passed but we do not have a model/database backed definition for e.g. virtual attributes.
147
- # if they are passed and we are not expecting them, our inputs will filter them out as they apply an additional level
148
- # of filtering
149
162
  unbacked = attributes - strong_parameters_definition.keys
150
163
 
151
- # attributes backed by some model/database definition
152
- # {:name=>{:name=>nil}, :body=>{:body=>nil}, :cover_image=>{:cover_image=>nil}, :comments=>{:comment_ids=>[]}}
153
- backed = strong_parameters_definition.
154
- # {:name=>{:name=>nil}, :comments=>{:comment_ids=>[]}, :cover_image=>{:cover_image=>nil}}
155
- slice(*attributes).
156
- # [{:name=>nil}, {:comment_ids=>[]}, {:cover_image=>nil}]
157
- values.
158
- # {:name=>nil, :comment_ids=>[], :cover_image=>nil}
159
- reduce(:merge)&.
160
- # [:name, {:comment_ids=>[]}, :cover_image]
161
- map { |key, value| value.nil? ? key : {key => value} } || {}
164
+ backed = strong_parameters_definition.slice(*attributes).values.reduce(:merge)
165
+ &.map { |key, value| value.nil? ? key : {key => value} } || {}
162
166
 
163
- unbacked + backed
167
+ case backed.presence
168
+ when Hash
169
+ [*unbacked, **backed]
170
+ when Array
171
+ [*unbacked, *backed]
172
+ when nil
173
+ unbacked
174
+ else
175
+ raise "Unexpected strong parameters definition: #{backed.class}"
176
+ end
177
+ end
178
+
179
+ # Finds the association to the given record
180
+ # @param [ActiveRecord::Base] record The record to find the association with
181
+ # @return [ActiveRecord::Reflection::AssociationReflection, nil]
182
+ def find_association_to_record(record)
183
+ reflect_on_all_associations.find do |assoc|
184
+ assoc.klass.name == record.class.name
185
+ rescue
186
+ assoc.check_validity!
187
+ raise
188
+ end
189
+ end
190
+
191
+ # Finds the association to self in the given record
192
+ # @param [ActiveRecord::Base] record The record to find the association with
193
+ # @return [ActiveRecord::Reflection::AssociationReflection, nil]
194
+ def find_association_to_self(record)
195
+ record.class.reflect_on_all_associations.find do |assoc|
196
+ assoc.klass.name == name
197
+ rescue
198
+ assoc.check_validity!
199
+ raise
200
+ end
201
+ end
202
+
203
+ # Queries based on the association type
204
+ # @param [ActiveRecord::Reflection::AssociationReflection] assoc The association
205
+ # @param [ActiveRecord::Base] record The record to query with
206
+ # @return [ActiveRecord::Relation]
207
+ def query_based_on_association(assoc, record)
208
+ case assoc.macro
209
+ when :has_one
210
+ joins(assoc.name).where(assoc.name => {record.class.primary_key => record.id})
211
+ when :belongs_to
212
+ where(assoc.name => record)
213
+ when :has_many
214
+ joins(assoc.name).where(assoc.klass.table_name => record)
215
+ else
216
+ raise NotImplementedError, "associated_with->##{assoc.macro}"
217
+ end
218
+ end
219
+
220
+ # Raises an error for unresolved associations
221
+ # @param [ActiveRecord::Base] record The record with unresolved association
222
+ # @param [Symbol] named_scope The named scope
223
+ # @raise [RuntimeError]
224
+ def raise_association_error(record, named_scope)
225
+ raise "Could not resolve the association between '#{name}' and '#{record.class.name}'\n\n" \
226
+ "Define\n" \
227
+ " 1. the associations between the models\n" \
228
+ " 2. a named scope on #{name} e.g.\n\n" \
229
+ "scope :#{named_scope}, ->(#{record.model_name.singular}) { do_something_here }"
164
230
  end
165
231
 
166
232
  private
167
233
 
234
+ # Defines the strong parameters
235
+ # @return [Hash]
168
236
  def strong_parameters_definition
169
237
  unless Rails.env.local?
170
238
  return @strong_parameters if defined?(@strong_parameters)
171
239
  end
172
240
 
173
- @strong_parameters = begin
174
- # Columns
175
-
176
- content_column_parameters = content_column_field_names.map do |name|
177
- column = columns_hash[name.to_s]
178
-
179
- type = nil
180
- type = [] if column&.try(:array?)
181
- type = {} if [:json, :jsonb].include?(column&.type)
241
+ @strong_parameters = build_strong_parameters
242
+ end
182
243
 
183
- [name, {name => type}]
244
+ # Builds the strong parameters hash
245
+ # @return [Hash]
246
+ def build_strong_parameters
247
+ parameters = content_column_field_names.map do |name|
248
+ column = columns_hash[name.to_s]
249
+ type = if column.try(:array?)
250
+ []
251
+ else
252
+ ([:json, :jsonb].include?(column&.type) ? {} : nil)
184
253
  end
185
- parameters = content_column_parameters.to_h
254
+ [name, {name => type}]
255
+ end.to_h
186
256
 
187
- # Associations
257
+ parameters.merge!(belongs_to_association_parameters)
258
+ parameters.merge!(has_many_association_parameters)
259
+ parameters.merge!(attachment_parameters)
260
+ parameters.merge!(nested_attributes_parameters)
188
261
 
189
- parameters.merge! reflect_on_all_associations(:belongs_to)
190
- .map { |reflection|
191
- input_param = reflection.respond_to?(:options) ? reflection.options[:foreign_key] : :"#{reflection.name}_id"
192
- [reflection.name, {input_param => nil}]
193
- }
194
- .to_h
195
-
196
- parameters.merge! has_many_association_field_names
197
- .map { |name| [name, {"#{name.to_s.singularize}_ids": []}] }
198
- .to_h
199
-
200
- # Attachments
201
-
202
- parameters.merge! has_many_attached_field_names.map { |name| [name, {name => []}] }.to_h
203
-
204
- parameters.merge! has_one_attached_field_names.map { |name| [name, {name => nil}] }.to_h
262
+ parameters
263
+ end
205
264
 
206
- # Nested Attributes
265
+ # Returns the parameters for belongs_to associations
266
+ # @return [Hash]
267
+ def belongs_to_association_parameters
268
+ reflect_on_all_associations(:belongs_to).map do |reflection|
269
+ input_param = reflection.options[:foreign_key] || :"#{reflection.name}_id"
270
+ [reflection.name, {input_param => nil}]
271
+ end.to_h
272
+ end
207
273
 
208
- parameters.merge! all_nested_attributes_options.keys
209
- .map { |name| [name, {"#{name}_attributes" => {}}] }
210
- .to_h
274
+ # Returns the parameters for has_many associations
275
+ # @return [Hash]
276
+ def has_many_association_parameters
277
+ has_many_association_field_names.map do |name|
278
+ [name, {"#{name.to_s.singularize}_ids": []}]
279
+ end.to_h
280
+ end
211
281
 
212
- # e.g.
213
- # {:name=>{:name=>nil}, :cover_image=>{:cover_image=>nil}, :user=>{:user_id=>nil} :comments=>{:comment_ids=>[]}}
214
- parameters
215
- end
282
+ # Returns the parameters for attachments
283
+ # @return [Hash]
284
+ def attachment_parameters
285
+ has_many_attached_field_names.map { |name| [name, {name => []}] }.to_h
286
+ .merge(has_one_attached_field_names.map { |name| [name, {name => nil}] }.to_h)
216
287
  end
217
288
 
218
- # Path parameters
289
+ # Returns the parameters for nested attributes
290
+ # @return [Hash]
291
+ def nested_attributes_parameters
292
+ all_nested_attributes_options.keys.map do |name|
293
+ [name, {"#{name}_attributes" => {}}]
294
+ end.to_h
295
+ end
219
296
 
297
+ # Defines a scope and method for path parameters
298
+ # @param [Symbol] param_name The name of the parameter
220
299
  def path_parameter(param_name)
221
300
  param_name = param_name.to_sym
222
301
 
@@ -225,10 +304,12 @@ module Plutonium
225
304
  define_method :to_param do
226
305
  return nil unless persisted?
227
306
 
228
- send param_name
307
+ send(param_name)
229
308
  end
230
309
  end
231
310
 
311
+ # Defines a scope and method for dynamic path parameters
312
+ # @param [Symbol] param_name The name of the parameter
232
313
  def dynamic_path_parameter(param_name)
233
314
  param_name = param_name.to_sym
234
315
 
@@ -240,8 +321,21 @@ module Plutonium
240
321
  "#{id}-#{send(param_name)}".parameterize
241
322
  end
242
323
  end
324
+
325
+ # Gathers all resource field names
326
+ # @return [Array<Symbol>]
327
+ def gather_resource_field_names
328
+ belongs_to_association_field_names +
329
+ has_one_attached_field_names +
330
+ has_one_association_field_names +
331
+ has_many_attached_field_names +
332
+ has_many_association_field_names +
333
+ content_column_field_names
334
+ end
243
335
  end
244
336
 
337
+ # Returns a label for the record
338
+ # @return [String]
245
339
  def to_label
246
340
  %i[name title].each do |method|
247
341
  name = send(method) if respond_to?(method)
@@ -6,6 +6,13 @@ module Plutonium
6
6
  included do
7
7
  layout "rodauth"
8
8
  append_view_path File.expand_path("app/views", Plutonium.root)
9
+ helper_method :application_name
10
+ end
11
+
12
+ private
13
+
14
+ def application_name
15
+ Rails.application.class.module_parent.name
9
16
  end
10
17
  end
11
18
  end
@@ -1,3 +1,3 @@
1
1
  module Plutonium
2
- VERSION = "0.10.1"
2
+ VERSION = "0.10.2"
3
3
  end
data/lib/plutonium.rb CHANGED
@@ -19,33 +19,71 @@ module Plutonium
19
19
  root.join("lib", "plutonium")
20
20
  end
21
21
 
22
+ def self.logger
23
+ Rails.logger
24
+ end
25
+
26
+ def self.development?
27
+ ActiveModel::Type::Boolean.new.cast(ENV["PLUTONIUM_DEV"]).present?
28
+ end
29
+
22
30
  def self.stylesheet_link
23
- if Plutonium::Config.development
31
+ return @stylesheet_link if defined?(@stylesheet_link) && !development?
32
+
33
+ if development?
24
34
  base_dir = "/plutonium-assets/build"
25
- manifest = "css.dev.manifest"
26
35
  filename = "plutonium-dev.css"
27
36
  else
28
37
  base_dir = "/plutonium-assets"
29
- manifest = "css.manifest"
30
38
  filename = "plutonium.css"
31
39
  end
32
40
 
33
- file = JSON.parse(File.read(root.join(manifest)))[filename]
34
- "#{base_dir}/#{file}"
41
+ file = stylesheet_manifest[filename]
42
+ @stylesheet_link = "#{base_dir}/#{file}"
35
43
  end
36
44
 
37
45
  def self.script_link
46
+ return @script_link if defined?(@script_link) && !development?
47
+
38
48
  filename = "plutonium-app.js"
39
- if Plutonium::Config.development
40
- base_dir = "/plutonium-assets/build"
41
- manifest = "js.dev.manifest"
49
+ base_dir = if development?
50
+ "/plutonium-assets/build"
42
51
  else
43
- base_dir = "/plutonium-assets"
44
- manifest = "js.manifest"
52
+ "/plutonium-assets"
53
+ end
54
+
55
+ file = script_manifest[filename]
56
+ @script_link = "#{base_dir}/#{file}"
57
+ end
58
+
59
+ def self.favicon_link
60
+ "/plutonium-assets/plutonium.ico"
61
+ end
62
+
63
+ def self.logo_link
64
+ "/plutonium-assets/plutonium-logo.png"
65
+ end
66
+
67
+ def self.stylesheet_manifest
68
+ return @stylesheet_manifest if defined?(@stylesheet_manifest) && !development?
69
+
70
+ manifest = if development?
71
+ "css.dev.manifest"
72
+ else
73
+ "css.manifest"
45
74
  end
75
+ @stylesheet_manifest = JSON.parse(File.read(root.join(manifest)))
76
+ end
77
+
78
+ def self.script_manifest
79
+ return @script_manifest if defined?(@script_manifest) && !development?
46
80
 
47
- file = JSON.parse(File.read(root.join(manifest)))[filename]
48
- "#{base_dir}/#{file}"
81
+ manifest = if development?
82
+ "js.dev.manifest"
83
+ else
84
+ "js.manifest"
85
+ end
86
+ @script_manifest = JSON.parse(File.read(root.join(manifest)))
49
87
  end
50
88
  end
51
89