提交 70e684a6 编写于 作者: J Jamis Buck

view_cache_dependency API

A declarative API for specifying dependencies that affect template
cache digest computation. In your controller, specify any of said
dependencies:

  view_cache_dependency { "phone" if using_phone? }

When the block is evaluated, the resulting value is included in the
cache digest calculation, allowing you to generate different digests
for effectively the same template. (Mostly useful if you're mucking
with template load paths.)
上级 ac86cbec
## Rails 4.0.0 (unreleased) ##
* Added view_cache_dependency API for declaring dependencies that affect
cache digest computation.
*Jamis Buck*
* `image_submit_tag` will set `alt` attribute from image source if not
specified.
......
......@@ -70,12 +70,30 @@ def self.page_cache_extension
config_accessor :perform_caching
self.perform_caching = true if perform_caching.nil?
class_attribute :_view_cache_dependencies
self._view_cache_dependencies = []
helper_method :view_cache_dependencies if respond_to?(:helper_method)
end
module ClassMethods
def view_cache_dependency(&dependency)
self._view_cache_dependencies += [dependency]
end
def view_cache_dependencies
_view_cache_dependencies.map { |dep| instance_exec &dep }.compact
end
end
def caching_allowed?
request.get? && response.status == 200
end
def view_cache_dependencies
self.class.view_cache_dependencies
end
protected
# Convenience accessor.
def cache(key, options = {}, &block)
......
......@@ -24,16 +24,17 @@ class Digestor
@@cache = ThreadSafe::Cache.new
def self.digest(name, format, finder, options = {})
@@cache["#{name}.#{format}"] ||= begin
cache_key = [name, format] + Array.wrap(options[:dependencies])
@@cache[cache_key.join('.')] ||= begin
klass = options[:partial] || name.include?("/_") ? PartialDigestor : Digestor
klass.new(name, format, finder).digest
klass.new(name, format, finder, options).digest
end
end
attr_reader :name, :format, :finder
attr_reader :name, :format, :finder, :options
def initialize(name, format, finder)
@name, @format, @finder = name, format, finder
def initialize(name, format, finder, options={})
@name, @format, @finder, @options = name, format, finder, options
end
def digest
......@@ -81,9 +82,11 @@ def source
end
def dependency_digest
dependencies.collect do |template_name|
template_digests = dependencies.collect do |template_name|
Digestor.digest(template_name, format, finder, partial: true)
end.join("-")
end
(template_digests + injected_dependencies).join("-")
end
def render_dependencies
......@@ -105,6 +108,10 @@ def render_dependencies
def explicit_dependencies
source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
end
def injected_dependencies
Array.wrap(options[:dependencies])
end
end
class PartialDigestor < Digestor # :nodoc:
......
......@@ -167,7 +167,7 @@ def fragment_name_with_digest(name) #:nodoc:
if @virtual_path
[
*Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name),
Digestor.digest(@virtual_path, formats.last.to_sym, lookup_context)
Digestor.digest(@virtual_path, formats.last.to_sym, lookup_context, dependencies: view_cache_dependencies)
]
else
name
......
......@@ -296,6 +296,24 @@ def test_safe_buffer
end
end
class ViewCacheDependencyTest < ActionController::TestCase
class NoDependenciesController < ActionController::Base
end
class HasDependenciesController < ActionController::Base
view_cache_dependency { "trombone" }
view_cache_dependency { "flute" }
end
def test_view_cache_dependencies_are_empty_by_default
assert NoDependenciesController.view_cache_dependencies.empty?
end
def test_view_cache_dependencies_are_listed_in_declaration_order
assert_equal %w(trombone flute), HasDependenciesController.view_cache_dependencies
end
end
class DeprecatedPageCacheExtensionTest < ActiveSupport::TestCase
def test_page_cache_extension_binds_default_static_extension
deprecation_behavior = ActiveSupport::Deprecation.behavior
......
......@@ -138,6 +138,20 @@ def test_old_style_hash_in_render_invocation
end
end
def test_dependencies_via_options_results_in_different_digest
digest_plain = digest("comments/_comment")
digest_fridge = digest("comments/_comment", dependencies: ["fridge"])
digest_phone = digest("comments/_comment", dependencies: ["phone"])
digest_fridge_phone = digest("comments/_comment", dependencies: ["fridge", "phone"])
assert_not_equal digest_plain, digest_fridge
assert_not_equal digest_plain, digest_phone
assert_not_equal digest_plain, digest_fridge_phone
assert_not_equal digest_fridge, digest_phone
assert_not_equal digest_fridge, digest_fridge_phone
assert_not_equal digest_phone, digest_fridge_phone
end
private
def assert_logged(message)
old_logger = ActionView::Base.logger
......@@ -164,8 +178,8 @@ def assert_digest_difference(template_name)
ActionView::Digestor.cache.clear
end
def digest(template_name)
ActionView::Digestor.digest(template_name, :html, FixtureFinder.new)
def digest(template_name, options={})
ActionView::Digestor.digest(template_name, :html, FixtureFinder.new, options)
end
def change_template(template_name)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册