mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #35623 from jhawthorn/actionview_cache
Make Template::Resolver always cache
This commit is contained in:
commit
d7e4cb87d3
6 changed files with 13 additions and 98 deletions
|
@ -22,11 +22,11 @@ module ActionView
|
||||||
# to ensure that references to the template object can be marshalled as well. This means forgoing
|
# 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.
|
# the marshalling of the compiler mutex and instantiating that again on unmarshalling.
|
||||||
def marshal_dump # :nodoc:
|
def marshal_dump # :nodoc:
|
||||||
[ @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant ]
|
[ @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant ]
|
||||||
end
|
end
|
||||||
|
|
||||||
def marshal_load(array) # :nodoc:
|
def marshal_load(array) # :nodoc:
|
||||||
@identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant = *array
|
@identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant = *array
|
||||||
@compile_mutex = Mutex.new
|
@compile_mutex = Mutex.new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -122,10 +122,10 @@ module ActionView
|
||||||
|
|
||||||
extend Template::Handlers
|
extend Template::Handlers
|
||||||
|
|
||||||
attr_reader :source, :identifier, :handler, :original_encoding, :updated_at
|
attr_reader :source, :identifier, :handler, :original_encoding
|
||||||
attr_reader :variable, :format, :variant, :locals, :virtual_path
|
attr_reader :variable, :format, :variant, :locals, :virtual_path
|
||||||
|
|
||||||
def initialize(source, identifier, handler, format: nil, variant: nil, locals: nil, virtual_path: nil, updated_at: Time.now)
|
def initialize(source, identifier, handler, format: nil, variant: nil, locals: nil, virtual_path: nil)
|
||||||
unless locals
|
unless locals
|
||||||
ActiveSupport::Deprecation.warn "ActionView::Template#initialize requires a locals parameter"
|
ActiveSupport::Deprecation.warn "ActionView::Template#initialize requires a locals parameter"
|
||||||
locals = []
|
locals = []
|
||||||
|
@ -144,7 +144,6 @@ module ActionView
|
||||||
$1.to_sym
|
$1.to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
@updated_at = updated_at
|
|
||||||
@format = format
|
@format = format
|
||||||
@variant = variant
|
@variant = variant
|
||||||
@compile_mutex = Mutex.new
|
@compile_mutex = Mutex.new
|
||||||
|
@ -261,11 +260,11 @@ module ActionView
|
||||||
# to ensure that references to the template object can be marshalled as well. This means forgoing
|
# 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.
|
# the marshalling of the compiler mutex and instantiating that again on unmarshalling.
|
||||||
def marshal_dump # :nodoc:
|
def marshal_dump # :nodoc:
|
||||||
[ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant ]
|
[ @source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant ]
|
||||||
end
|
end
|
||||||
|
|
||||||
def marshal_load(array) # :nodoc:
|
def marshal_load(array) # :nodoc:
|
||||||
@source, @identifier, @handler, @compiled, @locals, @virtual_path, @updated_at, @format, @variant = *array
|
@source, @identifier, @handler, @compiled, @locals, @virtual_path, @format, @variant = *array
|
||||||
@compile_mutex = Mutex.new
|
@compile_mutex = Mutex.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -63,26 +63,11 @@ module ActionView
|
||||||
|
|
||||||
# Cache the templates returned by the block
|
# Cache the templates returned by the block
|
||||||
def cache(key, name, prefix, partial, locals)
|
def cache(key, name, prefix, partial, locals)
|
||||||
if Resolver.caching?
|
|
||||||
@data[key][name][prefix][partial][locals] ||= canonical_no_templates(yield)
|
@data[key][name][prefix][partial][locals] ||= canonical_no_templates(yield)
|
||||||
else
|
|
||||||
fresh_templates = yield
|
|
||||||
cached_templates = @data[key][name][prefix][partial][locals]
|
|
||||||
|
|
||||||
if templates_have_changed?(cached_templates, fresh_templates)
|
|
||||||
@data[key][name][prefix][partial][locals] = canonical_no_templates(fresh_templates)
|
|
||||||
else
|
|
||||||
cached_templates || NO_TEMPLATES
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cache_query(query) # :nodoc:
|
def cache_query(query) # :nodoc:
|
||||||
if Resolver.caching?
|
|
||||||
@query_cache[query] ||= canonical_no_templates(yield)
|
@query_cache[query] ||= canonical_no_templates(yield)
|
||||||
else
|
|
||||||
yield
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear
|
def clear
|
||||||
|
@ -112,19 +97,6 @@ module ActionView
|
||||||
def canonical_no_templates(templates)
|
def canonical_no_templates(templates)
|
||||||
templates.empty? ? NO_TEMPLATES : templates
|
templates.empty? ? NO_TEMPLATES : templates
|
||||||
end
|
end
|
||||||
|
|
||||||
def templates_have_changed?(cached_templates, fresh_templates)
|
|
||||||
# if either the old or new template list is empty, we don't need to (and can't)
|
|
||||||
# compare modification times, and instead just check whether the lists are different
|
|
||||||
if cached_templates.blank? || fresh_templates.blank?
|
|
||||||
return fresh_templates.blank? != cached_templates.blank?
|
|
||||||
end
|
|
||||||
|
|
||||||
cached_templates_max_updated_at = cached_templates.map(&:updated_at).max
|
|
||||||
|
|
||||||
# if a template has changed, it will be now be newer than all the cached templates
|
|
||||||
fresh_templates.any? { |t| t.updated_at > cached_templates_max_updated_at }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
cattr_accessor :caching, default: true
|
cattr_accessor :caching, default: true
|
||||||
|
@ -218,8 +190,7 @@ module ActionView
|
||||||
virtual_path: path.virtual,
|
virtual_path: path.virtual,
|
||||||
format: format,
|
format: format,
|
||||||
variant: variant,
|
variant: variant,
|
||||||
locals: locals,
|
locals: locals
|
||||||
updated_at: mtime(template)
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -272,11 +243,6 @@ module ActionView
|
||||||
entry.gsub(/[*?{}\[\]]/, '\\\\\\&')
|
entry.gsub(/[*?{}\[\]]/, '\\\\\\&')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the file mtime from the filesystem.
|
|
||||||
def mtime(p)
|
|
||||||
File.mtime(p)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Extract handler, formats and variant from path. If a format cannot be found neither
|
# Extract handler, formats and variant from path. If a format cannot be found neither
|
||||||
# from the path, or the handler, we should return the array of formats given
|
# from the path, or the handler, we should return the array of formats given
|
||||||
# to the resolver.
|
# to the resolver.
|
||||||
|
|
|
@ -31,16 +31,14 @@ module ActionView #:nodoc:
|
||||||
query = /^(#{Regexp.escape(path)})#{query}$/
|
query = /^(#{Regexp.escape(path)})#{query}$/
|
||||||
|
|
||||||
templates = []
|
templates = []
|
||||||
@hash.each do |_path, array|
|
@hash.each do |_path, source|
|
||||||
source, updated_at = array
|
|
||||||
next unless query.match?(_path)
|
next unless query.match?(_path)
|
||||||
handler, format, variant = extract_handler_and_format_and_variant(_path)
|
handler, format, variant = extract_handler_and_format_and_variant(_path)
|
||||||
templates << Template.new(source, _path, handler,
|
templates << Template.new(source, _path, handler,
|
||||||
virtual_path: path.virtual,
|
virtual_path: path.virtual,
|
||||||
format: format,
|
format: format,
|
||||||
variant: variant,
|
variant: variant,
|
||||||
locals: locals,
|
locals: locals
|
||||||
updated_at: updated_at
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -326,12 +326,14 @@ class TemplateDigestorTest < ActionView::TestCase
|
||||||
|
|
||||||
def assert_digest_difference(template_name, options = {})
|
def assert_digest_difference(template_name, options = {})
|
||||||
previous_digest = digest(template_name, options)
|
previous_digest = digest(template_name, options)
|
||||||
|
finder.view_paths.each(&:clear_cache)
|
||||||
finder.digest_cache.clear
|
finder.digest_cache.clear
|
||||||
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
assert_not_equal previous_digest, digest(template_name, options), "digest didn't change"
|
assert_not_equal previous_digest, digest(template_name, options), "digest didn't change"
|
||||||
finder.digest_cache.clear
|
finder.digest_cache.clear
|
||||||
|
finder.view_paths.each(&:clear_cache)
|
||||||
end
|
end
|
||||||
|
|
||||||
def digest(template_name, options = {})
|
def digest(template_name, options = {})
|
||||||
|
|
|
@ -235,56 +235,6 @@ class LookupContextTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class LookupContextWithFalseCaching < ActiveSupport::TestCase
|
|
||||||
def setup
|
|
||||||
@resolver = ActionView::FixtureResolver.new("test/_foo.erb" => ["Foo", Time.utc(2000)])
|
|
||||||
@lookup_context = ActionView::LookupContext.new(@resolver, {})
|
|
||||||
end
|
|
||||||
|
|
||||||
test "templates are always found in the resolver but timestamp is checked before being compiled" do
|
|
||||||
ActionView::Resolver.stub(:caching?, false) do
|
|
||||||
template = @lookup_context.find("foo", %w(test), true)
|
|
||||||
assert_equal "Foo", template.source
|
|
||||||
|
|
||||||
# Now we are going to change the template, but it won't change the returned template
|
|
||||||
# since the timestamp is the same.
|
|
||||||
@resolver.data["test/_foo.erb"][0] = "Bar"
|
|
||||||
template = @lookup_context.find("foo", %w(test), true)
|
|
||||||
assert_equal "Foo", template.source
|
|
||||||
|
|
||||||
# Now update the timestamp.
|
|
||||||
@resolver.data["test/_foo.erb"][1] = Time.now.utc
|
|
||||||
template = @lookup_context.find("foo", %w(test), true)
|
|
||||||
assert_equal "Bar", template.source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "if no template was found in the second lookup, with no cache, raise error" do
|
|
||||||
ActionView::Resolver.stub(:caching?, false) do
|
|
||||||
template = @lookup_context.find("foo", %w(test), true)
|
|
||||||
assert_equal "Foo", template.source
|
|
||||||
|
|
||||||
@resolver.data.clear
|
|
||||||
assert_raise ActionView::MissingTemplate do
|
|
||||||
@lookup_context.find("foo", %w(test), true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "if no template was cached in the first lookup, retrieval should work in the second call" do
|
|
||||||
ActionView::Resolver.stub(:caching?, false) do
|
|
||||||
@resolver.data.clear
|
|
||||||
assert_raise ActionView::MissingTemplate do
|
|
||||||
@lookup_context.find("foo", %w(test), true)
|
|
||||||
end
|
|
||||||
|
|
||||||
@resolver.data["test/_foo.erb"] = ["Foo", Time.utc(2000)]
|
|
||||||
template = @lookup_context.find("foo", %w(test), true)
|
|
||||||
assert_equal "Foo", template.source
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class TestMissingTemplate < ActiveSupport::TestCase
|
class TestMissingTemplate < ActiveSupport::TestCase
|
||||||
def setup
|
def setup
|
||||||
@lookup_context = ActionView::LookupContext.new("/Path/to/views", {})
|
@lookup_context = ActionView::LookupContext.new("/Path/to/views", {})
|
||||||
|
|
Loading…
Reference in a new issue