With HTTP response headers you can the cache in the user's browser and proxies. Etags, Last-Modified, Cache-Control and Rack::Cache are all covered here
So, I've yet to see a good description of how to make caching play nicely with a user login status panel. You know, the little "logged in as John Smith" div that every Devise-based Rails app seems to have.
Obviously, you don't want this to be cached publicly, but then you lose all of that wonderful public cache goodness with Rack::Cache. I saw the conditional content bit at the end for public caching, but I'm not sure exactly how that would work -- does that mean that anyone who hits this page simply wouldn't see those elements? If so, how do you render flash notices or login status?
This -- the fact that there's usually just one or two parts of a complicated page that I DON'T want to cache publicly -- is what stops me from using public caching in Rails. I'd love to hear comments; it's quite possible that I am simply misunderstanding how it works. Maybe some more quality time with curl would help me...
Great point. Sometimes you can get by with making the status panel more generic such as "My Account" so it can work for any situation. However that isn't always wanted.
Alternatively you can use JavaScript to load the dynamic content. See Episode 169: Dynamic Page Caching on how to do this. I plan to revise that episode in the near future.
Does anyone know if you can simply bypass rack::cache for logged in users and still take advantage of http caching for 99% of my users that show up anonymous?
I set :public => !user_signed_in? accordingly, but rack::cache will still serve a public cached copy if it already had one to logged in users.
Any help would be appreciated! Thanks for the awesome railscast as always!
Setting :public => !user_signed_in? won't work, because when the first user comes, she won't be signed in and so the cache will be set, and when it gets set it won't hit the app to check it again.
I imagine you would have to override some behaviour in the rack::cache itself or put another middleware before it. But I don't think it would be worth it.
You should try the solution form epsiode #169 mentioned above. If you really want to get dirty with middlewares you can try to mix it with episode #205 on authentication with Warden, but as I said I doubt it's worth the effort. You'll just get into a mess that way.
My question is how I could bypass the rack::cache layer for logged in users.
I could certainly do #169's approach, but I'd far rather optimize for the 99%, leaving my code pretty much in tact, and just serve up the site to the very small % of logged in users. My actual in app caching is optimized enough I'm not too worried.
I will look into #305, but I've scoured the net and can't figure out a way to disable rack::cache for requests based on cookies, which is what I would need to do here.
To accomplish what your looking for, you can use the "force_pass" option in a middleware before the request hits rack-cache: https://gist.github.com/3836818
In the episode description:
With HTTP response headers you can the cache in the user's browser and proxies. Etags, Last-Modified, Cache-Control and Rack::Cache are all covered here
on the minute 5.11 you show your development log, wich is very clean. did you clean it up by hand?
why i ask? because since rails 3.1 (i think) i get this annoying ouput on every request:
WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
as far as i search, this is a bug on webrick that i couldn't find a workaround. i also test with Thin, but there's a bunch of other information that i don't want either. i just want a clean log as you show it!
Does 304 show up as a page view and work with say, google analytics? Since it's a local javascript, one would think it would get called again, but I'm not sure how the browser handles a 304.
But I'd love to see more info on this. It seems like with rail's asset compilation, the max-age could be a year or more, since the url/filename will change with new new push. But please correct me if I'm wrong.
Hi Ryan, I'd like to congratulate you for this wonderful job at railscasts.com. I'd love to see a screencast on how this Http caching techniques would play with something like Varnish cache or any other reverse-proxy/cache system.
FYI, If you're trying this in your own app and not seeing the etag headers, it could be because MiniProfiler (described in episode #368) strips the etag headers and rewrites the cache-control header. See my comment in that episode: http://railscasts.com/episodes/368-miniprofiler?view=comments#comment_159804
I could be missing something, but for me, fresh_when does not catch changes made to files and update the last modified or etag (e.g., layout, view or partial changes). I can check the modified time of each file that the action depends on, but that seems inelegant and is very error prone. Does anyone have a good solution? Or am I missing something?
If you remove the csrf_meta_tag from cached pages wouldn't that mean that those request is not safe against CSRF attacks? Is their any way to solve this problem?
So, I've yet to see a good description of how to make caching play nicely with a user login status panel. You know, the little "logged in as John Smith" div that every Devise-based Rails app seems to have.
Obviously, you don't want this to be cached publicly, but then you lose all of that wonderful public cache goodness with Rack::Cache. I saw the conditional content bit at the end for public caching, but I'm not sure exactly how that would work -- does that mean that anyone who hits this page simply wouldn't see those elements? If so, how do you render flash notices or login status?
This -- the fact that there's usually just one or two parts of a complicated page that I DON'T want to cache publicly -- is what stops me from using public caching in Rails. I'd love to hear comments; it's quite possible that I am simply misunderstanding how it works. Maybe some more quality time with curl would help me...
I was wondering the same thing. Right now I use partial caching with memcache which has helped a lot.
Well, one way is caching the whole page and loading user specific info like the logged in as box via ajax.
This is what I do and it works quite well.
Yep, I show how to do this in episode 169.
Great point. Sometimes you can get by with making the status panel more generic such as "My Account" so it can work for any situation. However that isn't always wanted.
Alternatively you can use JavaScript to load the dynamic content. See Episode 169: Dynamic Page Caching on how to do this. I plan to revise that episode in the near future.
+1 to revising episode 169.
Does anyone know if you can simply bypass rack::cache for logged in users and still take advantage of http caching for 99% of my users that show up anonymous?
I set :public => !user_signed_in? accordingly, but rack::cache will still serve a public cached copy if it already had one to logged in users.
Any help would be appreciated! Thanks for the awesome railscast as always!
Setting
:public => !user_signed_in?
won't work, because when the first user comes, she won't be signed in and so the cache will be set, and when it gets set it won't hit the app to check it again.I imagine you would have to override some behaviour in the rack::cache itself or put another middleware before it. But I don't think it would be worth it.
You should try the solution form epsiode #169 mentioned above. If you really want to get dirty with middlewares you can try to mix it with episode #205 on authentication with Warden, but as I said I doubt it's worth the effort. You'll just get into a mess that way.
Right. I get why it wasn't working.
My question is how I could bypass the rack::cache layer for logged in users.
I could certainly do #169's approach, but I'd far rather optimize for the 99%, leaving my code pretty much in tact, and just serve up the site to the very small % of logged in users. My actual in app caching is optimized enough I'm not too worried.
I will look into #305, but I've scoured the net and can't figure out a way to disable rack::cache for requests based on cookies, which is what I would need to do here.
To accomplish what your looking for, you can use the "force_pass" option in a middleware before the request hits rack-cache: https://gist.github.com/3836818
It seems like an appropriate episode to reviseā¦ Thanks Ryan!
Thanks for taking the time to explain this, it's always nice to see all the options and how it affects the http header. Keep up the good work!
+1 for dynamic page caching revised...
In the episode description:
With HTTP response headers you can the cache in the user's browser and proxies. Etags, Last-Modified, Cache-Control and Rack::Cache are all covered here
Should there be "used"?
one question here:
on the minute 5.11 you show your development log, wich is very clean. did you clean it up by hand?
why i ask? because since rails 3.1 (i think) i get this annoying ouput on every request:
WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
as far as i search, this is a bug on webrick that i couldn't find a workaround. i also test with Thin, but there's a bunch of other information that i don't want either. i just want a clean log as you show it!
Does 304 show up as a page view and work with say, google analytics? Since it's a local javascript, one would think it would get called again, but I'm not sure how the browser handles a 304.
One thing I didn't see mentioned about Rack::Cache - it should be used to set a max-age on your static assets (css and js) right?
I've set this in production.rb and it seems to work:
But I'd love to see more info on this. It seems like with rail's asset compilation, the max-age could be a year or more, since the url/filename will change with new new push. But please correct me if I'm wrong.
Hi Ryan, I'd like to congratulate you for this wonderful job at railscasts.com. I'd love to see a screencast on how this Http caching techniques would play with something like Varnish cache or any other reverse-proxy/cache system.
Long live to railscasts!
Came to this episode pretty late. I would also love to see an episode on Varnish cache with Rails.
FYI, If you're trying this in your own app and not seeing the etag headers, it could be because MiniProfiler (described in episode #368) strips the etag headers and rewrites the cache-control header. See my comment in that episode: http://railscasts.com/episodes/368-miniprofiler?view=comments#comment_159804
Thanks man, your note just saved me a lot of time!
To disable MiniProfiler temporarily, just append ?pp=disable to the URL.
Wow, thanks!
I tried to figure out what's wrong with my headers for 20 mins before I decided to check the internets. You saved my day!
I could be missing something, but for me, fresh_when does not catch changes made to files and update the last modified or etag (e.g., layout, view or partial changes). I can check the modified time of each file that the action depends on, but that seems inelegant and is very error prone. Does anyone have a good solution? Or am I missing something?
If you remove the
csrf_meta_tag
from cached pages wouldn't that mean that those request is not safe against CSRF attacks? Is their any way to solve this problem?Instead of curl -I I advise curl -v. The curl -I could change the server behaviour like in case of grape based apis.