Create a gist now

Instantly share code, notes, and snippets.

Poor man's caching for Jbuilder
# app/views/users/_user.json.jbuilder
json.(user, :id, :name, :age, :gender)
class ApplicationController < ActionController::Base
def cached_jbuilder(obj, opts = {})
cache_key = (opts[:cache_key_prefix] || []) + Array.wrap(obj)
cached = read_fragment(cache_key)
if cached
out = view_context.raw cached
elsif obj.is_a?(Array)
out = ""
obj.each_index do |i|
is_last = (obj.length - 1 == i)
out += cached_jbuilder(obj[i], opts) + (!is_last ? "," : "")
out = "[#{out}]"
write_fragment cache_key, out
out = view_context.raw render_to_string partial: obj, locals: { obj.class.to_s.tableize.to_sym => obj }
write_fragment cache_key, out
view_context.raw out
<% # app/views/users/index.json.erb -%>
{"users":<%= controller.cached_jbuilder @users -%>}

The idea behind this is to start building the JSON output through an ERB template. We can then easily use the caching helpers to partially or entirely cache the resulting JSON.

In this example, if @users is populated with 3 records when we render index.json.erb, a total of 4 cache keys will be created: 3 JSON string representations of each user, and 1 JSON string containing all 3 users in an array. If one user changes, the array cache is busted, as well as the cache for the record that has changed.

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