Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails fragment caching rendered liquid template

With ERB you can fragment cache individual records in a list view like so:

<% @items.each do |item| %>
  <% cache item do %>
    <%= item.name %>
  <% end %>
<% end %>

Thus, the second time the list is viewed, each rendered item will be loaded from cache. Is it possible to use this same approach when using Liquid templates? The template might look something like:

{% for item in items %}
  {{ item.name }}
{% endfor %}

and rendered with:

template = Liquid::Template.parse(template)
template.render('items' => @items)

When it loops over the items, I'd like to be able to fragment cache each one. Any pointers?

like image 396
imderek Avatar asked May 24 '12 01:05

imderek


1 Answers

You can define custom tags in liquid, for example if you put this in an initializer

class Cacher < Liquid::Block
  def initialize(tag_name, markup, tokens)
     super
    @key= markup.to_s
  end

  def render(context)
    Rails.cache.fetch(@key) do
      super
    end
  end
end

Liquid::Template.register_tag('cache', Cacher)

Then you can do

{% cache "some_key" %}
  ...
{% endcache %}

Be very careful with how you construct the cache key. You of course want to avoid clashes, but you also probably don't want people to be able to read arbitrary keys from your memcache store (which this code does). How match this matters depends on who has access to this in your app. One strategy would be to namespace cache keys.

like image 164
Frederick Cheung Avatar answered Oct 20 '22 23:10

Frederick Cheung