Generate Controller-Wide ETags [Rails 4 Countdown to 2013]

Posted on

This post is part of a series of 31 Rails 4 articles being released each day in December 2012.

One of the new features in Rails 4 is the ability to suffix controller-wide information to ETags. At the controller class level, you can set data by passing a block to the new etag macro style method. The etag method can be called multiple times, with each subsequent call suffixing the information to the response's ETag for easy client-side caching.

Here is an example of the usage of the etag method:

class NotesController < ApplicationController
  etag { current_user.try :id }

  def show
    @note = Note.find(params[:id])

Let's break down the code:

  • By using etag to include the id of the current user, we are ensuring that only that authenticated user will be able to generate the same ETag. This technique will prevent cached authorized pages from being accessible to other users.
  • If an Active Record model is passed into fresh_when, the response's ETag is set to the model's cache_key plus the current user id. The fresh_when method calls ActiveSupport::Cache.expand_cache_key behind the scenes. If we were using an array of items, instead of a single model, the ETag would include the cache_key of each item of the array and the current user id, all concatenated into a single unique identifier.
  • In the above example, we passed a single Active Record model to the fresh_when method. The code is equivalent to fresh_when(etag: @note, last_modified: @note.try(:updated_at)). This syntax sugar has been available since Rails 3.2.

Further Reading

For those of you interested in reading more about Conditional GET support in Rails, checkout the following links:


This post is by Kevin Faustino. Kevin is the Chief Craftsman of Remarkable Labs and also the founder of the Toronto Ruby Brigade.


comments powered by Disqus