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:
- Render the entire response body
- Create an ETag by doing a MD5 hash on the entire response body:
header['Etag'] = Digest::MD5.hexdigest(body)
- Send back to the client the response body and ETag included in the response
- If ETags match then the response body is not included in the response, only the 304 response code
Second Request on the same page:
- Render the entire response body
- Create ETag by doing a MD5 has on the entire response body:
header['Etag'] = Digest::MD5.hexdigest(body)
- Compares ETag with what was sent over and what it generated
- 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 cachekey is a combination of the model name, id and updatedat attribute.
'<model name>/<id>-<updated_at>'
'profile/2-201322415000'
Declarative ETags
Etags can be generated with multiple arguments. Which may something like this:
class ProfilesController < ApplicationController
def show
@profile = Profile.find(params[:id])
fresh_when([@profile, current_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