This blog is part of our Rails 5 series.
Let’s look at by default what kind of response headers we get when we start with a brand new Rails 4.2.4 application.
Now let’s say that I want to set a custom response header. That’s easy. All I need to do is add following line of code in the controller.
Now I see this custom response header.
Setting custom response header for assets
Let’s say that I need that custom response header not only for standard
web requests but also for my assets.
application.js file is served by Rails in localhost.
How would I set custom header to the asset being served by Rails here.
Actually that’s not possible in Rails 4. In Rails 4 we can set only one
response header for assets that are served by Rails and that response
Here is how I can configure
Cache-Control for assets.
Now we have modified ‘Cache-Control` header for the assets.
Cache-Control no other response header can be set for
assets served by Rails.
That’s a limitation.
How Rails Apps lived with this limitation so far
Rails is not the best server to serve static assets. Apace and NGINX are much better at this job. Hence ,in reality, in production almost everyone puts either Apache or NGINX in front of a Rails server and in this way Rails does not have to serve static files.
Havig said that, Rails applications hosted at Heroku is an exception. Assets for Rails applications running at Heroku are served by Rails application itself.
Problem we ran into
Here are how the header looked for
Now you see the problem we are running into.
- Our application is hosted at Heroku.
- Heroku lets Rails serve the assets.
- Google page speed insights wants us to set
Expiresheader to the assets.
- Rails application allows only one header for the assets and that is ‘Cache-Control`.
One easy solution is to host our website at Digital Ocean and then use Apache or NGINX.
Rails 5 saves the day
Recently Rails merged basic support for access control headers and added ability to define custom HTTP Headers on assets served by Rails.
Behind the scenes, Rails uses
ActionDispatch::Static middleware to take care of serving assets.
For example, a request to fetch an image, goes through
ActionDispatch::Static in the request cycle.
ActionDispatch::Static takes care of serving
Rack::File object from server with appropriate headers set in the
response. The served image can have headers like
Start using Rails master
To fix this, we first pointed the App to use Rails master.
Next, we changed asset configuration to start providing and using missing header for
Here, we are first setting the
Cache-Control header to use public (intermediate) caching,
for a year (31536000 seconds) with
s-maxage stands for
Surrogate cache, which is used to cache
internally by Fastly.
We then provide the missing
Expires value with some future date in Internet formatted time value.
With this setup, we can see PageSpeed pickups the new headers on assets and does not warn us for the missing header.
Here is the changed response header for asset.
For better use and more details about different headers to use for the assets, please refer to RFC 2616.