ETags in Rails 4 Image

ETags in Rails 4

July 20, 2013

What are ETags?


ETag or entity tag is part of HTTP that is assigned by a web server to a specific version of a resource found at URL. In other words, ETAG is a key we use to determine whether a page has changed.


ETags in Action


Here’s a diagram on how etags works:



Here’s a breakdown of how ETags works in Rails:


First Request 


1. Render the entire response body

2. Create an ETag by doing a MD5 hash on the entire response body:

header[‘Etag’] = Digest::MD5.hexdigest(body)

3. Send back to the client the response body and ETag included in the response


Second Request on the same page 


1. Render the entire response body

2. Create ETag by doing a MD5 has on the entire response body

header[‘Etag’] = Digest::MD5.hexdigest(body)

3. Compares ETag with what was sent over the what is generated

4. If ETags match then the response body is not included in the response, only the 304 response code


Custom ETags


Every time the server gets a request from client, it re-renders the page to generate the Etag, which is not that efficient. The solution for this is to create your own custom Etags with fresh_when method.


class ProfilesController < ApplicationController
  def show
    @profile = Profile.find(params[:id])
    fresh_when(@profile) # Sets the etag equal to the cache key
  end
end


fresh_when method creates a MD5 hash of the model


headers['Etag'] = Digest::MD5.hexdigest(@item.cache_key)


The cache_key is a combination of the model name, id and updated_at attribute.


'<model name>/<id>-<updated_at>'
  'profile/2-201322415000'



Creating Custom ETag


Here's a breakdown of how our custom ETag works:


First Request


1. Create an Etag from the model

2. Renders the entire response body

3. Send back to the client the response body and ETag


Second Request


1. Fetches the model

2. Create an ETag from the model

3. Compare the generated ETag from the one received from client

4. If ETags match then the response body is not included in the response, only the 304 response code


Declarative ETags


ETags can be generated with multiple arguments. Which make somehting like this:

class ProfilesController < ApplicationController
  def show
    @profile = Profile.find(params[:id])
    fresh_when([@profile, curernt_user.id])
  end
end


If we have multiple actions in our controller using ETags with multiple arguments, our code may end up looking like this:


class ProfilesController < ApplicationController
  def show
    @profile = Profile.find(params[:id])
    fresh_when([@profile, curernt_user.id])
  end

  def edit
    @profile = Profile.find(params[:id])
    fresh_when([@profile, curernt_user.id])
  end 
end


To make our code more DRY, we’ll use declarative ETags. Declarative ETags allows us to declare an ETag on top of our controller:


class ProfilesController < ApplicationController
  etag { current_user.id }
  def show
    @profile = Profile.find(params[:id])
    fresh_when(@profile)
  end

  def edit
    @profile = Profile.find(params[:id])
    fresh_when(@profile)
  end 
end


That’s it! Hopefully you’ve learned how to use ETags on your Rails 4 applications.