4

I am trying to interact with the cache store in a Rails app using Dalli. I am doing just fragment caching and have set up my dev config like this:

#config.action_controller.perform_caching = true
config.cache_store = :dalli_store

So that it isn't caching everything. The fragment I'm interested in caching is like this:

<% cache("home_main", :expires_in => 1.minute) do %>
<div class='tabbed-content content-1'>
  <%=render :partial => 'shared/launch-main', :locals => { :locations => @locations } %>
</div>
<% end %>

When I go in and run

ruby-1.9.2-p290 :019 > Rails.cache.stats
ruby-1.9.2-p290 :019 > y _

I get:

conn_yields: '0'
 bytes: '17153'
 curr_items: '1'
 total_items: '5'
 evictions: '0'
 reclaimed: '0'

Now is there a way to get back that fragement cache? Or to see it? I tried:

Rails.cache.fetch('home_main')

but that isn't working. Is there a way for me to see a list of cache keys?

thx

edit #1

for @cpuguy83 - so clearly going to DB with 196ms :-(

Read fragment views/home_main (2.4ms)
Rendered index/homepage_launch_main.html.erb (2.8ms)
Completed 200 OK in 1623ms (Views: 11.5ms | ActiveRecord: 195.8ms)
timpone
  • 19,235
  • 36
  • 121
  • 211

1 Answers1

5

Fragment caching prefixes the cache with your address and URL.... So your key ends up being something like:

localhost:3000/your/URL/cache_key

You can see what key it uses by looking at your dev logs.

Also, pulling the item out of the cache is done automatically with the call to cache in your view. When you load the page it is checking to see if the item in the cache is valid, if it is then it grabs it, if not it regenerates the HTML and stores it in your cache.

Also if you just want to read from the cache you should use Rails.cache.read, Rails.cache.fetch is generally to grab from the cache if the key is valid and if not write to the cache with the provided block.

So: Rails.cache.read your_cache_key will just read return whatever is stored with that cache key (if anything)

Fetch would be used like this:

Rails.cache.fetch your_cache_key do
  # Logic to generate items you want to cache
end

The call to <% cache @object do %> in your view is essentially a shortcut for Rails.cache.fetch

I would recommend changing your cache call to something like this:

<% cache ['home_main', @locations.order('updated_at DESC').first] do %>
    # your html here
<% end %>

In this case the cache key is based on the most recently updated location object. If a location is updated then the cache will miss on the next request and it will be re-generated. What cache is doing here is calling cache_key on your most recently updated location object. cache_key grabs the updated_at timestamp from your object and embeds that in the key used for storing your cached items.

Check out http://www.broadcastingadam.com/2012/07/advanced_caching_part_1-caching_strategies/ for a wonderful tutorial on caching. Also deals with really nice tricks for auto-expiring caches without the need of using time based cache expires or cache sweepers.

cpuguy83
  • 5,794
  • 4
  • 18
  • 24
  • thx for detailed answer, I'm trying to isolate these pieces as much as possible. When I write to file_store, it is writing to disk and expires it properly. I can see that it is calling to read fragment. However, it looks like it is still making database calls (see update 1 above). Any ideas why this is taking place – timpone Sep 16 '12 at 15:59
  • I would assume the database hits are from your controller action getting @locations. – cpuguy83 Sep 16 '12 at 17:07
  • thx, I'm getting closer; I really appreciate help. But dumb question - am i supposed to make that call to @locations=Location.get_homepage between the tags in the view? and hot have it in controller and just let the call to get the @locations instance variable happen in the view? – timpone Sep 16 '12 at 17:49
  • I wouldn't. Generally whatever I need to access I keep in the action, and then it also makes sure in my view I'm not making multiple DB calls for the same information. There are some advantages to doing it in the view... namely you can use Rails's support for HTTP streaming where it can send the headers, js, css to the user while it's building out the rest of the page, but this can introduce a lot of issues. – cpuguy83 Sep 16 '12 at 18:01
  • thx, so I probably wasn't fully clear. When you have @locations.order('updated_at DESC') in the call to cache, that @locations instance variable is what you are using in fragment cache and you are removing it from the controller? I ask because the query used is fairly complex and isn't used anywhere else (basically set numbers with randomization thrown in). I'm not so concerned about it being out of date for 5 or 10 minutes but I don't want people hitting home page to have an expensive database call. – timpone Sep 16 '12 at 18:24
  • Given that, would it make sense to put the call to @locations=Location.get_homepage in the view? thx again – timpone Sep 16 '12 at 18:24
  • If you can, order it that way in the controller (if it's ok for the template to show them in that order)... otherwise if it's an expensive call I'd figure out a different way to expire it... The point of the cache is to make requests nearly instant and reduce server load, if it's not doing it then caching (at least caching this way) is not the way to go. – cpuguy83 Sep 16 '12 at 18:36