0

I have just started using caching in a production application to speed things up. I've read the primary Rails guide, various blogs, the source itself, etc. But my head is still not clear on one simple thing when it comes to fragment caching:

When you destroy the cache after updating the object, are you only updating the single object, or the class? I think just the single object.

Here's an example:

<% @jobs.each do |job| %>
   <% cache("jobs_index_table_environment_#{session[:merchant_id]}_job_#{job}") do %>
    stuff
   <% end %>
<% end %>

I use the code above in my jobs index page. Each row is rendered with some information the user wants, some CSS, clickable to view the individual job, etc.

I wrote this in my Job class (model)

after_save do
    Rails.cache.delete("jobs_index_table_environment_#{merchant_id}_job_#{self}")
  end

  after_destroy do
    Rails.cache.delete("jobs_index_table_environment_#{merchant_id}_job_#{self}")
   end

I want the individual job objects destroyed from the cache if they are updated or destroyed, and of course newly created jobs get their own cache key the first time they pop on the page.

I don't do the Russian doll thing with @jobs because this is my "god" object and is changing all the time. The cache would almost never be helpful as the collection probably morphs by the minute.

Is my understanding correct that in the above view, if I rendered, say, 25 jobs to the first page, I would get 25 objects in my cache with the cache key, and then if I only change the first, it's cached value would be destroyed and the next time the jobs page loads, it would be re-cached while the other 24 would just be pulled from the cache?

halfer
  • 19,824
  • 17
  • 99
  • 186
notaceo
  • 1,093
  • 10
  • 28
  • If you read your terminal output you will should see lines that say "write fragment" or "read fragment". I think checking that out will help you figure out what your code is doing. – trosborn Sep 27 '15 at 19:15

1 Answers1

0

I'm a novice to fragment caching as well, and I just encountered a very similar use-case so I feel my (limited) knowledge is fresh enough to be of help.

Trosborn is correct, your terminal will highlight when you READ and when you WRITE, which shows you how many "hits" you got on your cache. It should only WRITE when you've changed an object. And based on what I see above, your delete is only deleting individual records.

However, I think there is a potentially simpler way to accomplish this, which is passing the ActiveRecord object to the cache, such as:

<% @jobs.each do |job| %>
   <% cache(job) do %>
    stuff
   <% end %>
<% end %>

Read this post from DHH on how this works. In short, when an AR object is passed to cache, the key is generated not just on the model name, but also on the id and the updated_at fields.

Obsolete fragments eventually get pushed out of the cache when memory runs out, so you don't need to worry about deleting old cache objects.

Lanny Bose
  • 1,811
  • 1
  • 11
  • 16
  • The complexity in my case is that 'job' gets rendered on various pages, and in practice when I tried the method you state, I was getting the CSS and all the other info of jobs/index on, say, customers/show where that job belonged to a specific customer. It's not enough to just give the cache the AR object. – notaceo Sep 29 '15 at 18:10
  • You could supplement the cache key with user: `cache [current_user, job]` or potentially prefix the key with a view-specific string: `cache ["this one view", current_user, job]`. Would that do the trick? – Lanny Bose Sep 29 '15 at 19:16
  • this is what I've already done in the initial post. The question is "does the cache invalidate all 25 records or just the record which changed?" I have unique keys setup correctly for the various pages. – notaceo Sep 30 '15 at 14:11
  • You're totally right. That makes sense. No, it would just invalidate the individual record. Again, though, you don't _have_ to delete the cache at all. The invalid one (as determined by the AR timestamp) will just get pushed out. I don't think there's anything inherently wrong with that choice. It's just not strictly necessary. – Lanny Bose Sep 30 '15 at 17:59