Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Adjust caching to use ActionView::Base#cache #67

Merged
merged 5 commits into from

3 participants

@rgarver

In an attempt to leverage some of the Rails primitives better I took a stab at refactoring the #cache! method to use the ActionView caching system instead of the Rails caching system directly. The hope is that this will enable support for cache_digests. Based on my initial tests it already honors the controller.perform_caching which makes sense for this. Any feed back on code here would be appreciated since I needed to get a little nasty with the output buffer to make it work.

@rgarver

Updated to leverage the great work by @rolftimmermans for 0.8.0. Still needed to do some monkey work to get things in the right formats, but the new helper that he introduced makes things much cleaner.

@rolftimmermans

Completely agree with the enhancement, but I can't help wondering if it's possible to achieve without the serialization/deserialization wizardry. Isn't it possible to reuse the internal API that is used in ActionView::Helpers::CacheHelper#cache? We really just need to call fragment_name_with_digest and controller.read/write_fragment, right?

@rgarver

The primary goal for going this route was to get cache_digest support. I wanted to avoid touching things too deep.

rails/cache_digests overrides ActionView::Helpers::CacheHelper#fragment_for which is used in ActionView::Helpers::CacheHelper#cache. We can work around it but we would then need to build cache_digests support custom. This approach keeps everything working the same even when the caching system is being modified in some way.

rails 4 is supposed to build cache_digests in so this might be moot.

@dhh
Owner
@rolftimmermans

It's probably necessary to duplicate some logic because we're storing objects, not strings. So controller.read/write_fragment won't work for Jbuilder, but perhaps we can at least reuse fragment_name_with_digest if it is present. That would introduce cache digest support for Rails master. Let me know if you want help, @rgarver.

@rgarver

Got it. That looks simple enough. I assume we'll want to patch rails to make that public. We'd probably also want to patch cache_digests to agree on the api since it inlines the fragment_name_with_digest function in to fragment_for.

@dhh
Owner
@rgarver

I've submitted patches. The cache_digests one might need to be brought inline with rails master a bit more, but I'm not sure what the motivations were that drove the divergence in the first place. Plus this isn't the place for that discussion.

See:
rails/cache_digests#5
rails/rails#7769

@dhh
Owner
dhh commented
lib/jbuilder_template.rb
((8 lines not shown))
_scope { yield self }
end
_merge(value)
end
+
+ protected
+ def _cache_key(key)
@dhh Owner
dhh added a note

Indent methods after the protected call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/jbuilder_template.rb
@@ -24,12 +24,21 @@ def partial!(options, locals = {})
# json.extract! @person, :name, :age
# end
def cache!(key=nil, options={}, &block)
- cache_key = ::ActiveSupport::Cache.expand_cache_key(key.is_a?(::Hash) ? url_for(key).split("://").last : key, :jbuilder)
- value = ::Rails.cache.fetch(cache_key, options) do
+ options[:force] = true unless @context.controller.perform_caching
+ value = ::Rails.cache.fetch(_cache_key(key), options) do
_scope { yield self }
end
_merge(value)
@dhh Owner
dhh added a note

Carrier return above the _merge call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@rgarver

Code style updated

@dhh dhh merged commit e0d9acc into rails:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 25, 2012
  1. @rgarver

    Change the #cache! method to use ActionView.cache so we can leverage …

    rgarver authored
    …controller.perform_caching and cache_digests in the future.
  2. @rgarver
Commits on Sep 26, 2012
  1. @rgarver

    Merge master 0.8.0

    rgarver authored
Commits on Sep 27, 2012
  1. @rgarver

    Revert back a bit to the old style (non-ActionView) but leverage frag…

    rgarver authored
    …ment_name_with_digest if available
Commits on Oct 4, 2012
  1. @rgarver

    Fix some code style issues

    rgarver authored
This page is out of date. Refresh to see the latest.
View
2  Gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- jbuilder (0.7.0)
+ jbuilder (0.8.0)
activesupport (>= 3.0.0)
GEM
View
14 lib/jbuilder_template.rb
@@ -24,12 +24,22 @@ def partial!(options, locals = {})
# json.extract! @person, :name, :age
# end
def cache!(key=nil, options={}, &block)
- cache_key = ::ActiveSupport::Cache.expand_cache_key(key.is_a?(::Hash) ? url_for(key).split("://").last : key, :jbuilder)
- value = ::Rails.cache.fetch(cache_key, options) do
+ options[:force] = true unless @context.controller.perform_caching
+ value = ::Rails.cache.fetch(_cache_key(key), options) do
_scope { yield self }
end
+
_merge(value)
end
+
+ protected
+ def _cache_key(key)
+ if @context.respond_to?(:fragment_name_with_digest)
+ @context.fragment_name_with_digest(key)
+ else
+ ::ActiveSupport::Cache.expand_cache_key(key.is_a?(::Hash) ? url_for(key).split("://").last : key, :jbuilder)
+ end
+ end
end
class JbuilderHandler
View
28 test/jbuilder_template_test.rb
@@ -8,9 +8,11 @@
module Rails
class Cache
def initialize
- @cache = {}
+ clear
end
+ def clear; @cache = {}; end
+
def write(k, v, opt={})
@cache[k] = v
end
@@ -78,32 +80,34 @@ def render_jbuilder(source)
end
test "fragment caching a JSON object" do
- json = render_jbuilder <<-JBUILDER
+ self.controller.perform_caching = true
+ Rails.cache.clear
+ render_jbuilder <<-JBUILDER
json.cache!("cachekey") do
json.name "Cache"
end
JBUILDER
- Rails.cache.read("jbuilder/cachekey").tap do |parsed|
- assert_equal "Cache", parsed['name']
- end
- end
-
- test "fragment caching deserializes a JSON object" do
- Rails.cache.write("jbuilder/cachekey", {'name' => "Something"})
json = render_jbuilder <<-JBUILDER
json.cache!("cachekey") do
- json.name "Cache"
+ json.name "Miss"
end
JBUILDER
MultiJson.load(json).tap do |parsed|
- assert_equal "Something", parsed['name']
+ assert_equal "Cache", parsed['name']
end
end
test "fragment caching deserializes an array" do
- Rails.cache.write("jbuilder/cachekey", ["a", "b", "c"])
+ Rails.cache.clear
+ self.controller.perform_caching = true
+ render_jbuilder <<-JBUILDER
+ json.cache!("cachekey") do
+ json.array! ['a', 'b', 'c']
+ end
+ JBUILDER
+
json = render_jbuilder <<-JBUILDER
json.cache!("cachekey") do
json.array! ['1', '2', '3']
Something went wrong with that request. Please try again.