Rails 3.1 and Http Page Caching - ruby-on-rails

Given that Heroku Cedar doesn't have http caching provided by Varnish I would like to use Rack::Cache.
I have been told that rails 3.1.1 have Rack::Cache active by default, I just need to make sure to have in the configuration:
config.action_controller.perform_caching = true
and I need to pick a cache store, for this experiment I'm using:
config.cache_store = :memory_store
In the action of the page I want to cache I've added the following lines:
response.header['Cache-Control'] = 'public, max-age=300'
response.header['Expires'] = CGI.rfc1123_date(Time.now + 300)
This code used to work fine with Varnish, the first request would return a 200 and the subsequent (for 5 mins) would return a 304.
This doesn't happen with Rails 3.1 and Heroku Cedar Stack.
I do get those headers in the response but subsequent requests returns 200 instead of 304.
What am I doing wrong? Thank you.

As you noted, the Cedar stack doesn't use Varnish. That means a web request will always hit the ruby server.
With that in mind, Rack::Cache will respect your headers and serve the cached content.
However, since the request is actually going past the http layer into the rails app, the response will always be 200 since the cache doesn't happen at the http layer anymore.
To confirm this is true, insert this in one of your cached actions:
<%= Time.now.to_i %>
Then, reload the page several times and you'll notice the timestamp won't change.

Related

Rail API - Disable cached response

I have a Rails 6 API-only application and I'm using Nginx and passenger.
When I try to do GET or POST in the Postman application or other places, I get only cached responses.
For instance, if I try to get user 1, movies, I'll get the correct ones, but if I change the JWT to user 2, I still see the previous response which was for user 1.
I have tried a few options such as:
In production.rb I added:
config.action_controller.perform_caching = false
config.cache_store = :null_store
I have also tried the controller level by adding: expires_now which in the header shows no-cache and also with expires_in 5.seconds, public: false which shows max-age=5, private as the header, but I still get the same response for any user.
you can use a command to disable cache in rails app: rails dev:cache

rack cache with X-Rack-Cache:miss

I setup rack cache with redis
config.action_dispatch.rack_cache = true
And it works but sometimes (way to often), caching doesn't work as expected. Event though cache headers are properly set Cache-Control:max-age=20, public, s-maxage=600 I see that response headers contain X-Rack-Cache:miss which means that URL was not in cache and it also didn't store the server response into cache store.
URL is like this (has 1 GET param for language):
http://localhost:3000/js/JAYy-euKaergqRsTlrn67w/events.js?lng=es
and if I add extra params or change the lng param to eg 'de' it than stores the response as expected. It seems like it acts a bit randomly.
I noticed this only on development environment - on production i seems like it always work as expected. What could be the reason?

Rails fragment caching not working locally

I've added the following at the top of my index.html.haml:
- cache do
content
And as far as I can see, the content is not cached. My server output shows that when I reload the page, it still fetches all the info from the database again.
I haven't tried on live as I don't want to push anything before it's 100% working. What am I doing wrong? Am I not understanding how it's supposed to work? I've set the config.action_controller.perform_caching = true.
cache_store configures which cache store to use for Rails caching so you need to specify that
You need to set cache store in general config.
config.cache_store = xyz,abc # PUT THIS
Options that you can set:
:memory_store, :file_store, :mem_cache_store

Rails http caching trying to write to tmp/cache. why?

My understanding was that to use http caching in Rails 3, all I had to do was add something like this to the action
expires_in(10.seconds, :public => true)
but when I do this, it tries to write to tmp/cache in addition to performing http caching in the browser (same user request for that action doesn't ever hit the server, as expected)
Why is this? How do I stop Rails from writing to the cache directory for http caching?
PS: I'm using nginx+passenger
The things that writes to /tmp/cache is Rack::Cache::FileStore that is configurable via config.cache_store; It's a rails3 native proxy-cache;
if you want to disable it:
config.action_dispatch.rack_cache = nil
Another solution is to not use the :public => true setting in expires_in. It appears that this setting is the reason why Rack::Cache writes the response to cache. If you set it to private => true (the default), this doesn't happen

Exclusively server-side caching of a Rails.app with Rack::Cache

I have the following problem: I want to cache the result of an action in Redis. For this reason, I use https://github.com/jodosha/redis-rack-cache. The fact that an action should be cached by Rack::Cache is determined by setting the appropriate HTTP header information in Rails, e.g.:
response.headers['Cache-Control'] = 'max-age=3600, public, must-revalidate'
Now, Rack::Cache will correctly cache the response in Redis. However, this header does also tell the browser to cache the response, which I don't want! The request should be cached exclusively on the server-side.
As a workaround, I am replacing the header in nginx, which I use as a reverse proxy, but there must be a more elegant way. Does anybody know how to do it?
Best regards,
Martin
One option would be to write your own middleware that sits above Rack::Cache and then removes these Cache-Control headers from the response.
Something as simple as:
def call(env)
status, headers, body = #app.call(env)
headers.delete("Cache-Control")
[status, headers, body]
end
would work as a middleware.

Resources