提交 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) ## ## 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 * `image_submit_tag` will set `alt` attribute from image source if not
specified. specified.
......
...@@ -70,12 +70,30 @@ def self.page_cache_extension ...@@ -70,12 +70,30 @@ def self.page_cache_extension
config_accessor :perform_caching config_accessor :perform_caching
self.perform_caching = true if perform_caching.nil? 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 end
def caching_allowed? def caching_allowed?
request.get? && response.status == 200 request.get? && response.status == 200
end end
def view_cache_dependencies
self.class.view_cache_dependencies
end
protected protected
# Convenience accessor. # Convenience accessor.
def cache(key, options = {}, &block) def cache(key, options = {}, &block)
......
...@@ -24,16 +24,17 @@ class Digestor ...@@ -24,16 +24,17 @@ class Digestor
@@cache = ThreadSafe::Cache.new @@cache = ThreadSafe::Cache.new
def self.digest(name, format, finder, options = {}) 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 = options[:partial] || name.include?("/_") ? PartialDigestor : Digestor
klass.new(name, format, finder).digest klass.new(name, format, finder, options).digest
end end
end end
attr_reader :name, :format, :finder attr_reader :name, :format, :finder, :options
def initialize(name, format, finder) def initialize(name, format, finder, options={})
@name, @format, @finder = name, format, finder @name, @format, @finder, @options = name, format, finder, options
end end
def digest def digest
...@@ -81,9 +82,11 @@ def source ...@@ -81,9 +82,11 @@ def source
end end
def dependency_digest def dependency_digest
dependencies.collect do |template_name| template_digests = dependencies.collect do |template_name|
Digestor.digest(template_name, format, finder, partial: true) Digestor.digest(template_name, format, finder, partial: true)
end.join("-") end
(template_digests + injected_dependencies).join("-")
end end
def render_dependencies def render_dependencies
...@@ -105,6 +108,10 @@ def render_dependencies ...@@ -105,6 +108,10 @@ def render_dependencies
def explicit_dependencies def explicit_dependencies
source.scan(EXPLICIT_DEPENDENCY).flatten.uniq source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
end end
def injected_dependencies
Array.wrap(options[:dependencies])
end
end end
class PartialDigestor < Digestor # :nodoc: class PartialDigestor < Digestor # :nodoc:
......
...@@ -167,7 +167,7 @@ def fragment_name_with_digest(name) #:nodoc: ...@@ -167,7 +167,7 @@ def fragment_name_with_digest(name) #:nodoc:
if @virtual_path if @virtual_path
[ [
*Array(name.is_a?(Hash) ? controller.url_for(name).split("://").last : name), *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 else
name name
......
...@@ -296,6 +296,24 @@ def test_safe_buffer ...@@ -296,6 +296,24 @@ def test_safe_buffer
end end
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 class DeprecatedPageCacheExtensionTest < ActiveSupport::TestCase
def test_page_cache_extension_binds_default_static_extension def test_page_cache_extension_binds_default_static_extension
deprecation_behavior = ActiveSupport::Deprecation.behavior deprecation_behavior = ActiveSupport::Deprecation.behavior
......
...@@ -138,6 +138,20 @@ def test_old_style_hash_in_render_invocation ...@@ -138,6 +138,20 @@ def test_old_style_hash_in_render_invocation
end end
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 private
def assert_logged(message) def assert_logged(message)
old_logger = ActionView::Base.logger old_logger = ActionView::Base.logger
...@@ -164,8 +178,8 @@ def assert_digest_difference(template_name) ...@@ -164,8 +178,8 @@ def assert_digest_difference(template_name)
ActionView::Digestor.cache.clear ActionView::Digestor.cache.clear
end end
def digest(template_name) def digest(template_name, options={})
ActionView::Digestor.digest(template_name, :html, FixtureFinder.new) ActionView::Digestor.digest(template_name, :html, FixtureFinder.new, options)
end end
def change_template(template_name) def change_template(template_name)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册