Reputation: 6697
I have a simple controller that I have responding to both html
and json
. I'm using the json
response for a Backbone app. Everything works as expected, except that when I click a link that uses the show
method, and then click the back button, the index
method just prints a big string of JSON
into the browser. If I refresh, it displays HTML as expected. Here's the controller.
class RecipesController < ApplicationController
def index
@user = User.find(params[:user_id])
@recipes = Recipe.all
respond_to do |format|
format.html
format.json { render json: Recipe.where(user_id: params[:user_id]).featured }
end
end
...
end
I tried adding a check for response.xhr?
, and only rendering JSON
if it was an AJAX request, but that didn't work.
This is a Rails 3 app not utilizing turbolinks.
Here is the relevant Backbone code.
# app/assets/javascripts/collections/recipe_list_.js.cofee
@App.Collections.RecipeList = Backbone.Collection.extend
url: ->
"/users/#{@userId}/recipes"
model: window.App.Models.Recipe
initialize: (opts) ->
@userId = opts.userId
# app/assets/javascripts/app.js.coffee
$ ->
urlAry = window.location.href.split('/')
userId = urlAry[urlAry.length - 2]
App = window.App
App.recipeList = new App.Collections.RecipeList(userId: userId)
App.recipeListView = new App.Views.RecipeListView
Upvotes: 8
Views: 1676
Reputation: 3640
If you're referring to a chrome and turbolinks issue, then an easy fix is to disable caching on ajax requests:
$.ajaxSetup({cache: false})
Upvotes: 4
Reputation: 13181
I bet it's due to turbolink, or ajax based page rendering (backbone, remote=true
, ...)
I always disable turbolink and keep control over which links are remote=true
, and for all ajax response I insert this javascript line at the end
history.pushState(null, '', '/the/requested/url' );
If you don't want to manually implement this line for each of your link responses, you can wrap it in an ajax:complete
event (more info), and I assume turbolink has an event you can use as well.
Second part of the trick is to bind popstate
so when your users click on the "back" button the page will be refreshed from the server (through the url that was pushState-ed earlier) and the ajax/js/json/whatever response won't be displayed anymore.
setTimeout( function () {
$(window).bind('popstate', function () {
window.location = location.href;
});
}, 500);
As you see I wrap the popstate event binding in a setTimeout
, because if you don't do that you may have trouble with some browser that would infinitely refresh the page.
Upvotes: 3
Reputation: 736
Are you using Chrome? if so this is a known issue. When you hit the back button chromes serves the page from cache since what was returned was json that is what it dumps on the screen. This post has some suggested workarounds
https://code.google.com/p/chromium/issues/detail?id=108766
Upvotes: 2
Reputation: 154
you could try using /recipes.html and /recipes.json and /recipes/1.html and /recipes/1.json
instead of relying on backbone and history to always send the correct headers
Upvotes: 3