---
title: "Rails 5 switches from strong etags to weak etags"
description: "Rails 5 switches from strong etags to weak etags"
canonical_url: "https://www.bigbinary.com/blog/rails-5-switches-from-strong-etags-to-weak-tags"
markdown_url: "https://www.bigbinary.com/blog/rails-5-switches-from-strong-etags-to-weak-tags.md"
---

# Rails 5 switches from strong etags to weak etags

Rails 5 switches from strong etags to weak etags

- Author: Prajakta Tambe
- Published: March 8, 2016
- Categories: Rails 5, Rails

[ETag](https://en.wikipedia.org/wiki/HTTP_ETag), short for entity tag, is a part
of HTTP header and is used for web cache validation. ETag is a digest of the
resource that uniquely identifies specific version of the resource. This helps
browser and web servers determine if resource in the browser's cache is exactly
same as the resource on the server.

### Strong v/s Weak ETags

ETag supports
[strong and weak validation](https://tools.ietf.org/html/rfc2616#section-13.3.3)
of the resource.

Strong ETag indicates that resource content is same for response body and the
response headers.

Weak ETag indicates that the two representations are semantically equivalent. It
compares only the response body.

Weak ETags are
[prefixed with](https://github.com/rails/rails/blob/a61bf5f5b63780a3e0b4c2d4339967df82b370de/actionpack/lib/action_dispatch/http/cache.rb#L91-L94)
`W\` and thus one can easily distinguish between Weak ETags and Strong ETags.

```plaintext
"543b39c23d8d34c232b457297d38ad99"    – Strong ETag
W/"543b39c23d8d34c232b457297d38ad99"  – Weak ETag
```

W3 has
[an example](https://www.w3.org/Protocols/HTTP/1.1/rfc2616bis/issues/#i71) page
to illustrate how ETag matching works.

When server receives a request, it returns an ETag header as part of HTTP
response. This ETag represents state of the resource. For the subsequent HTTP
requests, client sends this ETag via `If-None-Match` header to identify if the
resource is changed or not. The server will compare the current ETag and the one
sent by the client. If ETag matches, server responds with `304 Not modified`.
This means resource content in the client's cache is up-to-date. If resource is
changed, server will send updated resource along with the new ETag.

Let's see it in action.

## ETags in Rails 4.x

Rails 4.x generates strong ETags by default i.e without `W/` prefix.

```ruby
class ItemsController < ApplicationController
  def show
    @item = Item.find(params[:id])
    fresh_when @item
  end
end
```

We are making first request to the server.

```plaintext
$ curl -i http://localhost:3000/items/1

HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Etag: "618bbc92e2d35ea1945008b42799b0e7"
Last-Modified: Sat, 30 Jan 2016 08:02:12 GMT
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 98359119-14ae-4e4e-8174-708abbc3fd4b
X-Runtime: 0.412232
Server: WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)
Date: Fri, 04 Mar 2016 10:50:38 GMT
Content-Length: 1014
Connection: Keep-Alive
```

For the next request, we will send ETag that was sent by the sever. And notice
that server returns `304 Not Modified`.

```plaintext
$ curl -i -H 'If-None-Match: "618bbc92e2d35ea1945008b42799b0e7"' http://localhost:3000/items/1

HTTP/1.1 304 Not Modified
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Etag: "618bbc92e2d35ea1945008b42799b0e7"
Last-Modified: Sat, 30 Jan 2016 08:02:12 GMT
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: e4447f82-b96c-4482-a5ff-4f5003910c18
X-Runtime: 0.012878
Server: WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)
Date: Fri, 04 Mar 2016 10:51:22 GMT
Connection: Keep-Alive
```

## Rails 5 sets Weak ETags by default

In Rails 5, all ETags generated by Rails will be
[weak by default](https://github.com/rails/rails/pull/17573).

```plaintext
$ curl -i http://localhost:3000/items/1

HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Etag: W/"b749c4dd1b20885128f9d9a1a8ba70b6"
Last-Modified: Sat, 05 Mar 2016 00:00:00 GMT
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: a24b986c-74f0-4e23-9b1d-0b52cb3ef906
X-Runtime: 0.038372
Server: WEBrick/1.3.1 (Ruby/2.2.3/2015-08-18)
Date: Fri, 04 Mar 2016 10:48:35 GMT
Content-Length: 1906
Connection: Keep-Alive
```

Now for the second request, server will return `304 Not Modified` response as
before, but the ETag is weak ETag.

```plaintext
$ curl -i -H 'If-None-Match: W/"b749c4dd1b20885128f9d9a1a8ba70b6"' http://localhost:3000/items/1

HTTP/1.1 304 Not Modified
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Etag: W/"b749c4dd1b20885128f9d9a1a8ba70b6"
Last-Modified: Sat, 05 Mar 2016 00:00:00 GMT
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 7fc8a8b9-c7ff-4600-bf9b-c847201973cc
X-Runtime: 0.005469
Server: WEBrick/1.3.1 (Ruby/2.2.3/2015-08-18)
Date: Fri, 04 Mar 2016 10:49:27 GMT
Connection: Keep-Alive
```

## Why this change?

Rails does not perform strong validation of ETags as implied by strong ETags
spec. Rails just checks whether the incoming ETag from the request headers
matches with the ETag of the generated response. It does not do byte by byte
comparison of the response.

This was true even before Rails 5. So this change is more of a course
correction. Rack also
[generates weak ETags](https://github.com/rack/rack/issues/681) by default
because of similar reasons.

[Mark Notthingham](https://twitter.com/mnot) is chair of
[HTTP Working Group](http://httpwg.org) and he
[has written about etags](https://www.mnot.net/blog/2007/08/07/etags) which has
some useful links to other ETag resources.

### How to use strong ETags in Rails 5

If we want to bypass default Rails 5 behavior to use strong ETags then we can do
by following way.

```ruby

class ItemsController < ApplicationController
  def show
    @item = Item.find(params[:id])
    fresh_when strong_etag: @item
  end
end

```

This will generate strong Etag i.e without `W/` prefix.

## Links

- [Human page](https://www.bigbinary.com/blog/rails-5-switches-from-strong-etags-to-weak-tags)
