1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Introduce a file type template, deprecate Template#refresh

Every template that specifies a "virtual path" loses the template source
when the template gets compiled:

  eda0f574f1/actionview/lib/action_view/template.rb (L275)

The "refresh" method seems to think that the source code for a template
can be recovered if there is a virtual path:

  eda0f574f1/actionview/lib/action_view/template.rb (L171-L188)

Every call site that allocates a template object *and* provides a
"virtual path" reads the template contents from the filesystem:

  eda0f574f1/actionview/lib/action_view/template/resolver.rb (L229-L231)

Templates that are inline or literals don't provide a "virtual path":

  eda0f574f1/actionview/lib/action_view/renderer/template_renderer.rb (L34)

This commit introduces a `FileTemplate` type that subclasses `Template`.
The `FileTemplate` keeps a reference to the filename, and reads the
source from the filesystem.  This effectively makes the template source
immutable.

Other classes depended on the source to be mutated while being compiled,
so this commit also introduces a temporary way to pass the mutated
source to the ERB (or whatever) compiler.  See `LegacyTemplate`.

I think we should consider it an error to provide a virtual path on a
non file type template an non-file templates can't recover their source.
Here is an example:

  eda0f574f1/actionview/lib/action_view/testing/resolvers.rb (L53)

This provides a "virtual path" so the source code (a string literal) is
thrown away after compilation.  Clearly we can't recover that string, so
I think this should be an error.
This commit is contained in:
Aaron Patterson 2019-01-31 15:34:09 -08:00
parent 916b74d16a
commit 2169bd3d2a
No known key found for this signature in database
GPG key ID: 953170BCB4FFAFC6
4 changed files with 47 additions and 3 deletions

View file

@ -45,6 +45,7 @@ module ActionView
autoload :Rendering autoload :Rendering
autoload :RoutingUrlFor autoload :RoutingUrlFor
autoload :Template autoload :Template
autoload :FileTemplate
autoload :ViewPaths autoload :ViewPaths
autoload_under "renderer" do autoload_under "renderer" do

View file

@ -0,0 +1,33 @@
# frozen_string_literal: true
require "action_view/template"
module ActionView
class FileTemplate < Template
def initialize(filename, handler, details)
@filename = filename
super(nil, filename, handler, details)
end
def source
File.binread @filename
end
def refresh(_)
self
end
# Exceptions are marshalled when using the parallel test runner with DRb, so we need
# to ensure that references to the template object can be marshalled as well. This means forgoing
# the marshalling of the compiler mutex and instantiating that again on unmarshalling.
def marshal_dump # :nodoc:
[ @identifier, @handler, @compiled, @original_encoding, @locals, @virtual_path, @updated_at, @formats, @variants ]
end
def marshal_load(array) # :nodoc:
@identifier, @handler, @compiled, @original_encoding, @locals, @virtual_path, @updated_at, @formats, @variants = *array
@compile_mutex = Mutex.new
end
end
end

View file

@ -2,7 +2,9 @@
require "active_support/core_ext/object/try" require "active_support/core_ext/object/try"
require "active_support/core_ext/kernel/singleton_class" require "active_support/core_ext/kernel/singleton_class"
require "active_support/deprecation"
require "thread" require "thread"
require "delegate"
module ActionView module ActionView
# = Action View Template # = Action View Template
@ -279,6 +281,15 @@ module ActionView
end end
end end
class LegacyTemplate < DelegateClass(Template) # :nodoc:
attr_reader :source
def initialize(template, source)
super(template)
@source = source
end
end
# Among other things, this method is responsible for properly setting # Among other things, this method is responsible for properly setting
# the encoding of the compiled template. # the encoding of the compiled template.
# #
@ -293,7 +304,7 @@ module ActionView
# regardless of the original source encoding. # regardless of the original source encoding.
def compile(mod) def compile(mod)
source = encode! source = encode!
code = @handler.call(self) code = @handler.call(LegacyTemplate.new(self, source))
# Make sure that the resulting String to be eval'd is in the # Make sure that the resulting String to be eval'd is in the
# encoding of the code # encoding of the code

View file

@ -226,9 +226,8 @@ module ActionView
template_paths.map do |template| template_paths.map do |template|
handler, format, variant = extract_handler_and_format_and_variant(template) handler, format, variant = extract_handler_and_format_and_variant(template)
contents = File.binread(template)
Template.new(contents, File.expand_path(template), handler, FileTemplate.new(File.expand_path(template), handler,
virtual_path: path.virtual, virtual_path: path.virtual,
format: format, format: format,
variant: variant, variant: variant,