actionview 6.0.0.beta1 → 6.0.1.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionview might be problematic. Click here for more details.

Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +90 -3
  3. data/README.rdoc +3 -1
  4. data/lib/action_view.rb +2 -1
  5. data/lib/action_view/base.rb +107 -10
  6. data/lib/action_view/cache_expiry.rb +54 -0
  7. data/lib/action_view/context.rb +0 -5
  8. data/lib/action_view/digestor.rb +8 -17
  9. data/lib/action_view/gem_version.rb +2 -2
  10. data/lib/action_view/helpers/asset_tag_helper.rb +5 -5
  11. data/lib/action_view/helpers/cache_helper.rb +5 -5
  12. data/lib/action_view/helpers/csp_helper.rb +4 -2
  13. data/lib/action_view/helpers/form_helper.rb +2 -2
  14. data/lib/action_view/helpers/form_options_helper.rb +4 -3
  15. data/lib/action_view/helpers/form_tag_helper.rb +5 -2
  16. data/lib/action_view/helpers/output_safety_helper.rb +1 -1
  17. data/lib/action_view/helpers/rendering_helper.rb +6 -4
  18. data/lib/action_view/helpers/sanitize_helper.rb +10 -16
  19. data/lib/action_view/helpers/tag_helper.rb +1 -1
  20. data/lib/action_view/helpers/tags/base.rb +1 -1
  21. data/lib/action_view/helpers/translation_helper.rb +3 -3
  22. data/lib/action_view/helpers/url_helper.rb +2 -2
  23. data/lib/action_view/layouts.rb +5 -5
  24. data/lib/action_view/lookup_context.rb +69 -27
  25. data/lib/action_view/path_set.rb +5 -10
  26. data/lib/action_view/railtie.rb +9 -4
  27. data/lib/action_view/renderer/abstract_renderer.rb +56 -3
  28. data/lib/action_view/renderer/partial_renderer.rb +66 -55
  29. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +27 -20
  30. data/lib/action_view/renderer/renderer.rb +16 -4
  31. data/lib/action_view/renderer/streaming_template_renderer.rb +4 -4
  32. data/lib/action_view/renderer/template_renderer.rb +24 -18
  33. data/lib/action_view/rendering.rb +46 -27
  34. data/lib/action_view/template.rb +84 -69
  35. data/lib/action_view/template/error.rb +21 -1
  36. data/lib/action_view/template/handlers.rb +27 -1
  37. data/lib/action_view/template/handlers/builder.rb +2 -2
  38. data/lib/action_view/template/handlers/erb.rb +5 -5
  39. data/lib/action_view/template/handlers/erb/erubi.rb +7 -3
  40. data/lib/action_view/template/handlers/html.rb +1 -1
  41. data/lib/action_view/template/handlers/raw.rb +2 -2
  42. data/lib/action_view/template/html.rb +14 -5
  43. data/lib/action_view/template/inline.rb +22 -0
  44. data/lib/action_view/template/raw_file.rb +28 -0
  45. data/lib/action_view/template/resolver.rb +80 -117
  46. data/lib/action_view/template/sources.rb +13 -0
  47. data/lib/action_view/template/sources/file.rb +17 -0
  48. data/lib/action_view/template/text.rb +5 -3
  49. data/lib/action_view/testing/resolvers.rb +33 -20
  50. data/lib/action_view/unbound_template.rb +32 -0
  51. data/lib/action_view/view_paths.rb +25 -1
  52. data/lib/assets/compiled/rails-ujs.js +21 -12
  53. metadata +25 -16
@@ -109,7 +109,7 @@ module ActionView
109
109
  end
110
110
  end
111
111
 
112
- def annoted_source_code
112
+ def annotated_source_code
113
113
  source_extract(4)
114
114
  end
115
115
 
@@ -138,4 +138,24 @@ module ActionView
138
138
  end
139
139
 
140
140
  TemplateError = Template::Error
141
+
142
+ class SyntaxErrorInTemplate < TemplateError #:nodoc
143
+ def initialize(template, offending_code_string)
144
+ @offending_code_string = offending_code_string
145
+ super(template)
146
+ end
147
+
148
+ def message
149
+ <<~MESSAGE
150
+ Encountered a syntax error while rendering template: check #{@offending_code_string}
151
+ MESSAGE
152
+ end
153
+
154
+ def annotated_source_code
155
+ @offending_code_string.split("\n").map.with_index(1) { |line, index|
156
+ indentation = " " * 4
157
+ "#{index}:#{indentation}#{line}"
158
+ }
159
+ end
160
+ end
141
161
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/deprecation"
4
+
3
5
  module ActionView #:nodoc:
4
6
  # = Action View Template Handlers
5
7
  class Template #:nodoc:
@@ -14,7 +16,7 @@ module ActionView #:nodoc:
14
16
  base.register_template_handler :erb, ERB.new
15
17
  base.register_template_handler :html, Html.new
16
18
  base.register_template_handler :builder, Builder.new
17
- base.register_template_handler :ruby, :source.to_proc
19
+ base.register_template_handler :ruby, lambda { |_, source| source }
18
20
  end
19
21
 
20
22
  @@template_handlers = {}
@@ -24,11 +26,35 @@ module ActionView #:nodoc:
24
26
  @@template_extensions ||= @@template_handlers.keys
25
27
  end
26
28
 
29
+ class LegacyHandlerWrapper < SimpleDelegator # :nodoc:
30
+ def call(view, source)
31
+ __getobj__.call(ActionView::Template::LegacyTemplate.new(view, source))
32
+ end
33
+ end
34
+
27
35
  # Register an object that knows how to handle template files with the given
28
36
  # extensions. This can be used to implement new template types.
29
37
  # The handler must respond to +:call+, which will be passed the template
30
38
  # and should return the rendered template as a String.
31
39
  def register_template_handler(*extensions, handler)
40
+ params = if handler.is_a?(Proc)
41
+ handler.parameters
42
+ else
43
+ handler.method(:call).parameters
44
+ end
45
+
46
+ unless params.find_all { |type, _| type == :req || type == :opt }.length >= 2
47
+ ActiveSupport::Deprecation.warn <<~eowarn
48
+ Single arity template handlers are deprecated. Template handlers must
49
+ now accept two parameters, the view object and the source for the view object.
50
+ Change:
51
+ >> #{handler}.call(#{params.map(&:last).join(", ")})
52
+ To:
53
+ >> #{handler}.call(#{params.map(&:last).join(", ")}, source)
54
+ eowarn
55
+ handler = LegacyHandlerWrapper.new(handler)
56
+ end
57
+
32
58
  raise(ArgumentError, "Extension is required") if extensions.empty?
33
59
  extensions.each do |extension|
34
60
  @@template_handlers[extension.to_sym] = handler
@@ -5,11 +5,11 @@ module ActionView
5
5
  class Builder
6
6
  class_attribute :default_format, default: :xml
7
7
 
8
- def call(template)
8
+ def call(template, source)
9
9
  require_engine
10
10
  "xml = ::Builder::XmlMarkup.new(:indent => 2);" \
11
11
  "self.output_buffer = xml.target!;" +
12
- template.source +
12
+ source +
13
13
  ";xml.target!;"
14
14
  end
15
15
 
@@ -28,8 +28,8 @@ module ActionView
28
28
 
29
29
  ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*")
30
30
 
31
- def self.call(template)
32
- new.call(template)
31
+ def self.call(template, source)
32
+ new.call(template, source)
33
33
  end
34
34
 
35
35
  def supports_streaming?
@@ -40,17 +40,17 @@ module ActionView
40
40
  true
41
41
  end
42
42
 
43
- def call(template)
43
+ def call(template, source)
44
44
  # First, convert to BINARY, so in case the encoding is
45
45
  # wrong, we can still find an encoding tag
46
46
  # (<%# encoding %>) inside the String using a regular
47
47
  # expression
48
- template_source = template.source.dup.force_encoding(Encoding::ASCII_8BIT)
48
+ template_source = source.dup.force_encoding(Encoding::ASCII_8BIT)
49
49
 
50
50
  erb = template_source.gsub(ENCODING_TAG, "")
51
51
  encoding = $2
52
52
 
53
- erb.force_encoding valid_encoding(template.source.dup, encoding)
53
+ erb.force_encoding valid_encoding(source.dup, encoding)
54
54
 
55
55
  # Always make sure we return a String in the default_internal
56
56
  erb.encode!
@@ -13,7 +13,7 @@ module ActionView
13
13
 
14
14
  # Dup properties so that we don't modify argument
15
15
  properties = Hash[properties]
16
- properties[:preamble] = "@output_buffer = output_buffer || ActionView::OutputBuffer.new;"
16
+ properties[:preamble] = ""
17
17
  properties[:postamble] = "@output_buffer.to_s"
18
18
  properties[:bufvar] = "@output_buffer"
19
19
  properties[:escapefunc] = ""
@@ -22,8 +22,12 @@ module ActionView
22
22
  end
23
23
 
24
24
  def evaluate(action_view_erb_handler_context)
25
- pr = eval("proc { #{@src} }", binding, @filename || "(erubi)")
26
- action_view_erb_handler_context.instance_eval(&pr)
25
+ src = @src
26
+ view = Class.new(ActionView::Base) {
27
+ include action_view_erb_handler_context._routes.url_helpers
28
+ class_eval("define_method(:_template) { |local_assigns, output_buffer| #{src} }", defined?(@filename) ? @filename : "(erubi)", 0)
29
+ }.empty
30
+ view._run(:_template, nil, {}, ActionView::OutputBuffer.new)
27
31
  end
28
32
 
29
33
  private
@@ -3,7 +3,7 @@
3
3
  module ActionView
4
4
  module Template::Handlers
5
5
  class Html < Raw
6
- def call(template)
6
+ def call(template, source)
7
7
  "ActionView::OutputBuffer.new #{super}"
8
8
  end
9
9
  end
@@ -3,8 +3,8 @@
3
3
  module ActionView
4
4
  module Template::Handlers
5
5
  class Raw
6
- def call(template)
7
- "#{template.source.inspect}.html_safe;"
6
+ def call(template, source)
7
+ "#{source.inspect}.html_safe;"
8
8
  end
9
9
  end
10
10
  end
@@ -1,15 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/deprecation"
4
+
3
5
  module ActionView #:nodoc:
4
6
  # = Action View HTML Template
5
7
  class Template #:nodoc:
6
8
  class HTML #:nodoc:
7
- attr_accessor :type
9
+ attr_reader :type
8
10
 
9
11
  def initialize(string, type = nil)
12
+ unless type
13
+ ActiveSupport::Deprecation.warn "ActionView::Template::HTML#initialize requires a type parameter"
14
+ type = :html
15
+ end
16
+
10
17
  @string = string.to_s
11
- @type = Types[type] || type if type
12
- @type ||= Types[:html]
18
+ @type = type
13
19
  end
14
20
 
15
21
  def identifier
@@ -26,9 +32,12 @@ module ActionView #:nodoc:
26
32
  to_str
27
33
  end
28
34
 
29
- def formats
30
- [@type.respond_to?(:ref) ? @type.ref : @type.to_s]
35
+ def format
36
+ @type
31
37
  end
38
+
39
+ def formats; Array(format); end
40
+ deprecate :formats
32
41
  end
33
42
  end
34
43
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView #:nodoc:
4
+ class Template #:nodoc:
5
+ class Inline < Template #:nodoc:
6
+ # This finalizer is needed (and exactly with a proc inside another proc)
7
+ # otherwise templates leak in development.
8
+ Finalizer = proc do |method_name, mod| # :nodoc:
9
+ proc do
10
+ mod.module_eval do
11
+ remove_possible_method method_name
12
+ end
13
+ end
14
+ end
15
+
16
+ def compile(mod)
17
+ super
18
+ ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionView #:nodoc:
4
+ # = Action View RawFile Template
5
+ class Template #:nodoc:
6
+ class RawFile #:nodoc:
7
+ attr_accessor :type, :format
8
+
9
+ def initialize(filename)
10
+ @filename = filename.to_s
11
+ extname = ::File.extname(filename).delete(".")
12
+ @type = Template::Types[extname] || Template::Types[:text]
13
+ @format = @type.symbol
14
+ end
15
+
16
+ def identifier
17
+ @filename
18
+ end
19
+
20
+ def render(*args)
21
+ ::File.read(@filename)
22
+ end
23
+
24
+ def formats; Array(format); end
25
+ deprecate :formats
26
+ end
27
+ end
28
+ end
@@ -63,26 +63,11 @@ module ActionView
63
63
 
64
64
  # Cache the templates returned by the block
65
65
  def cache(key, name, prefix, partial, locals)
66
- if Resolver.caching?
67
- @data[key][name][prefix][partial][locals] ||= canonical_no_templates(yield)
68
- else
69
- fresh_templates = yield
70
- cached_templates = @data[key][name][prefix][partial][locals]
71
-
72
- if templates_have_changed?(cached_templates, fresh_templates)
73
- @data[key][name][prefix][partial][locals] = canonical_no_templates(fresh_templates)
74
- else
75
- cached_templates || NO_TEMPLATES
76
- end
77
- end
66
+ @data[key][name][prefix][partial][locals] ||= canonical_no_templates(yield)
78
67
  end
79
68
 
80
69
  def cache_query(query) # :nodoc:
81
- if Resolver.caching?
82
- @query_cache[query] ||= canonical_no_templates(yield)
83
- else
84
- yield
85
- end
70
+ @query_cache[query] ||= canonical_no_templates(yield)
86
71
  end
87
72
 
88
73
  def clear
@@ -112,19 +97,6 @@ module ActionView
112
97
  def canonical_no_templates(templates)
113
98
  templates.empty? ? NO_TEMPLATES : templates
114
99
  end
115
-
116
- def templates_have_changed?(cached_templates, fresh_templates)
117
- # if either the old or new template list is empty, we don't need to (and can't)
118
- # compare modification times, and instead just check whether the lists are different
119
- if cached_templates.blank? || fresh_templates.blank?
120
- return fresh_templates.blank? != cached_templates.blank?
121
- end
122
-
123
- cached_templates_max_updated_at = cached_templates.map(&:updated_at).max
124
-
125
- # if a template has changed, it will be now be newer than all the cached templates
126
- fresh_templates.any? { |t| t.updated_at > cached_templates_max_updated_at }
127
- end
128
100
  end
129
101
 
130
102
  cattr_accessor :caching, default: true
@@ -143,35 +115,33 @@ module ActionView
143
115
 
144
116
  # Normalizes the arguments and passes it on to find_templates.
145
117
  def find_all(name, prefix = nil, partial = false, details = {}, key = nil, locals = [])
146
- cached(key, [name, prefix, partial], details, locals) do
147
- find_templates(name, prefix, partial, details)
148
- end
149
- end
118
+ locals = locals.map(&:to_s).sort!.freeze
150
119
 
151
- def find_all_anywhere(name, prefix, partial = false, details = {}, key = nil, locals = [])
152
120
  cached(key, [name, prefix, partial], details, locals) do
153
- find_templates(name, prefix, partial, details, true)
121
+ _find_all(name, prefix, partial, details, key, locals)
154
122
  end
155
123
  end
156
124
 
125
+ alias :find_all_anywhere :find_all
126
+ deprecate :find_all_anywhere
127
+
157
128
  def find_all_with_query(query) # :nodoc:
158
129
  @cache.cache_query(query) { find_template_paths(File.join(@path, query)) }
159
130
  end
160
131
 
161
132
  private
162
133
 
134
+ def _find_all(name, prefix, partial, details, key, locals)
135
+ find_templates(name, prefix, partial, details, locals)
136
+ end
137
+
163
138
  delegate :caching?, to: :class
164
139
 
165
140
  # This is what child classes implement. No defaults are needed
166
141
  # because Resolver guarantees that the arguments are present and
167
142
  # normalized.
168
- def find_templates(name, prefix, partial, details, outside_app_allowed = false)
169
- raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details, outside_app_allowed = false) method"
170
- end
171
-
172
- # Helpers that builds a path. Useful for building virtual paths.
173
- def build_path(name, prefix, partial)
174
- Path.build(name, prefix, partial)
143
+ def find_templates(name, prefix, partial, details, locals = [])
144
+ raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details, locals = []) method"
175
145
  end
176
146
 
177
147
  # Handles templates caching. If a key is given and caching is on
@@ -180,25 +150,13 @@ module ActionView
180
150
  # resolver is fresher before returning it.
181
151
  def cached(key, path_info, details, locals)
182
152
  name, prefix, partial = path_info
183
- locals = locals.map(&:to_s).sort!
184
153
 
185
154
  if key
186
155
  @cache.cache(key, name, prefix, partial, locals) do
187
- decorate(yield, path_info, details, locals)
156
+ yield
188
157
  end
189
158
  else
190
- decorate(yield, path_info, details, locals)
191
- end
192
- end
193
-
194
- # Ensures all the resolver information is set in the template.
195
- def decorate(templates, path_info, details, locals)
196
- cached = nil
197
- templates.each do |t|
198
- t.locals = locals
199
- t.formats = details[:formats] || [:html] if t.formats.empty?
200
- t.variants = details[:variants] || [] if t.variants.empty?
201
- t.virtual_path ||= (cached ||= build_path(*path_info))
159
+ yield
202
160
  end
203
161
  end
204
162
  end
@@ -209,34 +167,60 @@ module ActionView
209
167
  DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}"
210
168
 
211
169
  def initialize(pattern = nil)
212
- @pattern = pattern || DEFAULT_PATTERN
170
+ if pattern
171
+ ActiveSupport::Deprecation.warn "Specifying a custom path for #{self.class} is deprecated. Implement a custom Resolver subclass instead."
172
+ @pattern = pattern
173
+ else
174
+ @pattern = DEFAULT_PATTERN
175
+ end
176
+ @unbound_templates = Concurrent::Map.new
177
+ super()
178
+ end
179
+
180
+ def clear_cache
181
+ @unbound_templates.clear
213
182
  super()
214
183
  end
215
184
 
216
185
  private
217
186
 
218
- def find_templates(name, prefix, partial, details, outside_app_allowed = false)
187
+ def _find_all(name, prefix, partial, details, key, locals)
219
188
  path = Path.build(name, prefix, partial)
220
- query(path, details, details[:formats], outside_app_allowed)
189
+ query(path, details, details[:formats], locals, cache: !!key)
221
190
  end
222
191
 
223
- def query(path, details, formats, outside_app_allowed)
192
+ def query(path, details, formats, locals, cache:)
224
193
  template_paths = find_template_paths_from_details(path, details)
225
- template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed
194
+ template_paths = reject_files_external_to_app(template_paths)
226
195
 
227
196
  template_paths.map do |template|
228
- handler, format, variant = extract_handler_and_format_and_variant(template)
229
- contents = File.binread(template)
230
-
231
- Template.new(contents, File.expand_path(template), handler,
232
- virtual_path: path.virtual,
233
- format: format,
234
- variant: variant,
235
- updated_at: mtime(template)
236
- )
197
+ unbound_template =
198
+ if cache
199
+ @unbound_templates.compute_if_absent([template, path.virtual]) do
200
+ build_unbound_template(template, path.virtual)
201
+ end
202
+ else
203
+ build_unbound_template(template, path.virtual)
204
+ end
205
+
206
+ unbound_template.bind_locals(locals)
237
207
  end
238
208
  end
239
209
 
210
+ def build_unbound_template(template, virtual_path)
211
+ handler, format, variant = extract_handler_and_format_and_variant(template)
212
+ source = Template::Sources::File.new(template)
213
+
214
+ UnboundTemplate.new(
215
+ source,
216
+ template,
217
+ handler,
218
+ virtual_path: virtual_path,
219
+ format: format,
220
+ variant: variant,
221
+ )
222
+ end
223
+
240
224
  def reject_files_external_to_app(files)
241
225
  files.reject { |filename| !inside_path?(@path, filename) }
242
226
  end
@@ -285,11 +269,6 @@ module ActionView
285
269
  entry.gsub(/[*?{}\[\]]/, '\\\\\\&')
286
270
  end
287
271
 
288
- # Returns the file mtime from the filesystem.
289
- def mtime(p)
290
- File.mtime(p)
291
- end
292
-
293
272
  # Extract handler, formats and variant from path. If a format cannot be found neither
294
273
  # from the path, or the handler, we should return the array of formats given
295
274
  # to the resolver.
@@ -301,51 +280,25 @@ module ActionView
301
280
 
302
281
  handler = Template.handler_for_extension(extension)
303
282
  format, variant = pieces.last.split(EXTENSIONS[:variants], 2) if pieces.last
304
- format &&= Template::Types[format]
283
+ format = if format
284
+ Template::Types[format]&.ref
285
+ else
286
+ if handler.respond_to?(:default_format) # default_format can return nil
287
+ handler.default_format
288
+ else
289
+ nil
290
+ end
291
+ end
305
292
 
293
+ # Template::Types[format] and handler.default_format can return nil
306
294
  [handler, format, variant]
307
295
  end
308
296
  end
309
297
 
310
- # A resolver that loads files from the filesystem. It allows setting your own
311
- # resolving pattern. Such pattern can be a glob string supported by some variables.
312
- #
313
- # ==== Examples
314
- #
315
- # Default pattern, loads views the same way as previous versions of rails, eg. when you're
316
- # looking for <tt>users/new</tt> it will produce query glob: <tt>users/new{.{en},}{.{html,js},}{.{erb,haml},}</tt>
317
- #
318
- # FileSystemResolver.new("/path/to/views", ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}")
319
- #
320
- # This one allows you to keep files with different formats in separate subdirectories,
321
- # eg. <tt>users/new.html</tt> will be loaded from <tt>users/html/new.erb</tt> or <tt>users/new.html.erb</tt>,
322
- # <tt>users/new.js</tt> from <tt>users/js/new.erb</tt> or <tt>users/new.js.erb</tt>, etc.
323
- #
324
- # FileSystemResolver.new("/path/to/views", ":prefix/{:formats/,}:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}")
325
- #
326
- # If you don't specify a pattern then the default will be used.
327
- #
328
- # In order to use any of the customized resolvers above in a Rails application, you just need
329
- # to configure ActionController::Base.view_paths in an initializer, for example:
330
- #
331
- # ActionController::Base.view_paths = FileSystemResolver.new(
332
- # Rails.root.join("app/views"),
333
- # ":prefix/:action{.:locale,}{.:formats,}{+:variants,}{.:handlers,}",
334
- # )
335
- #
336
- # ==== Pattern format and variables
337
- #
338
- # Pattern has to be a valid glob string, and it allows you to use the
339
- # following variables:
340
- #
341
- # * <tt>:prefix</tt> - usually the controller path
342
- # * <tt>:action</tt> - name of the action
343
- # * <tt>:locale</tt> - possible locale versions
344
- # * <tt>:formats</tt> - possible request formats (for example html, json, xml...)
345
- # * <tt>:variants</tt> - possible request variants (for example phone, tablet...)
346
- # * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...)
347
- #
298
+ # A resolver that loads files from the filesystem.
348
299
  class FileSystemResolver < PathResolver
300
+ attr_reader :path
301
+
349
302
  def initialize(path, pattern = nil)
350
303
  raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
351
304
  super(pattern)
@@ -365,6 +318,10 @@ module ActionView
365
318
 
366
319
  # An Optimized resolver for Rails' most common case.
367
320
  class OptimizedFileSystemResolver < FileSystemResolver #:nodoc:
321
+ def initialize(path)
322
+ super(path)
323
+ end
324
+
368
325
  private
369
326
 
370
327
  def find_template_paths_from_details(path, details)
@@ -420,12 +377,18 @@ module ActionView
420
377
  # The same as FileSystemResolver but does not allow templates to store
421
378
  # a virtual path since it is invalid for such resolvers.
422
379
  class FallbackFileSystemResolver < FileSystemResolver #:nodoc:
380
+ private_class_method :new
381
+
423
382
  def self.instances
424
383
  [new(""), new("/")]
425
384
  end
426
385
 
427
- def decorate(*)
428
- super.each { |t| t.virtual_path = nil }
386
+ def build_unbound_template(template, _)
387
+ super(template, nil)
388
+ end
389
+
390
+ def reject_files_external_to_app(files)
391
+ files
429
392
  end
430
393
  end
431
394
  end