Being served a response directly from the cache when clicking back button
backbone.js, browser-history, caching, pushstate, ruby-on-rails
Solution
You can add a no-cache header to your response on the server-side, this should instruct the browser to not cache the response:
response.headers["Cache-Control"] = "no-cache"
Problem
Note that I don't think this problem is related to Backbone or JavaScript but it is necessary to include some Backbone code as context on the issue. The Related Code I have a client-side Backbone router with a route which takes a parameter called `contactId`. It looks similar to this: ``` Backbone.Router.extend({ routes: { "jobs/new?contact_id=:contactId": "newForContact" }, // Fetch the contact and initialize a new job model which // is associated with that contact. newForContact: function(contactId) { var contact = new Contact(id: contactId); contact.fetch({ success: _.bind(function(model, resp) { var job = new Job(contact: contact); this.new(job); } }, this)); }, // Show the JobView for the given job. new: function(jobModel) { view = new JobView(job: jobModel); $('body').append(view.render().el); } }; ``` Now I'm trying to use this setup with `pushState` turned on. When I hit the route which triggers the `newForContact` route, everything works as expected. However, if I press the browser's back button at this point, I am served the JSON response from the `contact.fetch()` method straight out of the browser's cache. No request is sent to the server. The App Logs You can see this in the Rails app logs. In this part, I visit the route which triggers `newForContact`. ``` Started GET "/jobs/new?contact%5Bid%5D=1&contact%5Btype%5D=Customer" for 127.0.0.1 at 2012-10-31 22:41:48 +0000 Processing by JobsController#new as HTML Parameters: {"contact"=>{"id"=>"1", "type"=>"Customer"}} User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]] Business Load (0.3ms) SELECT "businesses".* FROM "businesses" WHERE "businesses"."id" IN (1) Rendered shared/_search_form.html.erb (0.3ms) Job Load (0.4ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."business_id" = 1 ORDER BY created_at desc Rendered jobs/_list.html.erb (1.5ms) Rendered jobs/index.html.erb within layouts/application (4.1ms) Rendered layouts/_head_content.html.erb (0.7ms) Rendered layouts/_flash.html.erb (0.0ms) Cache read: views/jobs/main_nav/d6a805d9b6f285e424f207add4f35595 Read fragment views/jobs/main_nav/d6a805d9b6f285e424f207add4f35595 (0.4ms) Rendered layouts/_nav.html.erb (0.6ms) Rendered layouts/_header.html.erb (0.7ms) Completed 200 OK in 12ms (Views: 8.0ms | ActiveRecord: 1.0ms) Cache read: http://print.dev/customers/1? ``` You can see that it fetches the contact at this point with a JSON request. ``` Started GET "/customers/1" for 127.0.0.1 at 2012-10-31 22:41:48 +0000 Processing by CustomersController#show as JSON Parameters: {"id"=>"1"} User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]] Business Load (0.4ms) SELECT "businesses".* FROM "businesses" WHERE "businesses"."id" IN (1) Customer Load (0.2ms) SELECT "customers".* FROM "customers" WHERE "customers"."business_id" = 1 AND "customers"."id" = $1 LIMIT 1 [["id", "1"]] CustomerEmployee Load (0.3ms) SELECT "customer_employees".* FROM "customer_employees" WHERE "customer_employees"."employer_id" IN (1) Job Load (0.4ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."contact_type" = 'Customer' AND "jobs"."contact_id" IN (1) Invoice Load (0.3ms) SELECT "invoices".* FROM "invoices" WHERE "invoices"."client_id" IN (1) Job Load (0.5ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."contact_id" = 1 AND "jobs"."contact_type" = 'Customer' AND "jobs"."state" = 'finished' AND "jobs"."invoice_id" IS NULL Rendered customers/show.json.rabl (2.8ms) Completed 200 OK in 67ms (Views: 3.2ms | ActiveRecord: 2.5ms) ``` At this point, I would press the browser's back button but no new request is logged at the server. Rails Environments This only happens on my staging server (Heroku), not in development. I can recreate it locally by running the app with Pow in the staging environment which has caching turned on in the rails configs. ``` config.action_controller.perform_caching = true ``` Note that even with caching turned on, I can't recreate the bug in the development environment. This issue occurs in `Chrome 22.0.1229.94`, `FF 16.0.2` and `Safari 6.0.1`. I'm using Rails `3.2.8`. Possibly Related Questions It seems like this guy was having a very similar problem to me. Live Sample If you really want to you can view the problem live on my staging server on Heroku. Steps to Repro (edit: these don't work any longer since I patched the problem). - Log in here with email: user@example.com and pass: foobar - Visit http://print-staging.herokuapp.com/customers/2. You should see a messed up looking dialog box open up. - Click the small "New job" link in the dialog. The page should change and a new dialog should open. - Click the browser back button.