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).
Back/forward cache (or bfcache) is a browser optimization that enables instant back and forward navigation. It significantly improves the browsing experience for users—especially those with slower networks or devices.
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"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With