Last Updated: September 14, 2018
·
7.278K
· ktusznio

Cache your partials, not the other way around.

It might seem nice and tidy to do this:

# items/index.json.jbuilder
json.items @items do
  json.partial! "item", item: item
end

# items/show.json.jbuilder
json.item do
  json.partial! "item", item: @item
end

# items/_items.json.jbuilder
json.cache! item do
  json(item, :id, :name, ...)
end

The templates are DRY and things are organized.

But tucking the call to cache! into the _item partial is a performance hit. Consider:

# items/index.json.jbuilder
json.items @items do
  json.cache! item do
    json.partial! "item", item: item
  end
end

# items/show.json.jbuilder
json.item do
  json.cache! item do
    json.partial! "item", item: @item
  end
end

# items/_items.json.jbuilder
json(item, :id, :name, ...)

While slightly more repetitive, this structure saves the calls to partial! once the cache is warm. Loading a partial isn't free, and the time it takes to load one up adds up when aggregated over x items per request, and y requests per minute.

4 Responses
Add your response

I'd love your feedback on this: https://github.com/joshblour/jbuilder_cache_multi

it uses fetch_multi in rails 4 to read all keys at once from the cache.

At first I was doing it the first way you described, then the second way, then I wrote this plugin to make it even faster.

over 1 year ago ·

Hey, that seems like a nice approach! Does it work with Rails 3?

over 1 year ago ·

It does! The thing is that Rails 3 doesn't give you a fetch_multi method, so it's up to whichever cache you are using to implement it. If the method doesn't exist, the gem will fall back on iterating over the collection (the second way you describe) so it becomes more of a convenience method than anything else :)

over 1 year ago ·

Thanks for pointing this out. I think the |item| block parameter is missing in your examples though.

over 1 year ago ·