Permalink
Browse files

Merge pull request #8818 from jamis/master

view_cache_dependency API
  • Loading branch information...
2 parents ac86cbe + 70e684a commit 64e3660ff0c0fd708fd4fc5455c54bf3d511032b @dhh dhh committed Jan 8, 2013
View
5 actionpack/CHANGELOG.md
@@ -1,5 +1,10 @@
## 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.
View
18 actionpack/lib/action_controller/caching.rb
@@ -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)
View
21 actionpack/lib/action_view/digestor.rb
@@ -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:
View
2 actionpack/lib/action_view/helpers/cache_helper.rb
@@ -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
View
18 actionpack/test/controller/caching_test.rb
@@ -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
View
18 actionpack/test/template/digestor_test.rb
@@ -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)

0 comments on commit 64e3660

Please sign in to comment.