Rails 3.1 возвращает исходный код Javascript, когда используется кнопка возврата

Моя основная цель

Приложение Rails, которое может загружать новый контент через Ajax при использовании HTML5 для поддержания состояния истории браузера. У меня супер базовая версия приложения, работающая на Heroku. Я также создал общедоступный репозиторий GitHub, чтобы более подробно рассмотреть приведенный ниже код.

Проблема

Я успешно реализовал базовое приложение, используя API истории браузера HTML5 (в какой-то момент я также сделал версию, используя плагин history.js jQuery). Все работает так, как нужно, пока пользователь не нажмет на ссылку не-ajax, а затем ударит кнопку "Назад" . Например, если пользователь щелкнул элемент 2, приложение успешно загрузило новое содержимое и изменило состояние браузера. Если они нажимают кнопку "Назад" , она также правильно перезагружает предыдущий контент и изменяет состояние браузера обратно в соответствии. Но если пользователь затем просматривает другую веб-страницу (любую другую страницу в Интернете), то нажимает кнопку своего браузера, приложение Rails отображает сырой javascript вместо исходной страницы.

Все работает до последнего шага, когда контроллер начинает возвращать необработанный javascript из show.js.erb вместо show.html.erb. Я попытался изменить несколько параметров в контроллере, но я не могу понять, что конкретно вызывает это. Я знаю, что если я удалю вызов history.pushState в show.js.erb, проблема остановится (хотя, очевидно, я потеряю все функции истории браузера, которые я искал в первую очередь).

Любые идеи?

Бонус: Мучительная деталь

Вот как все работает (я думаю!).

Пользователь нажимает на ссылку, которая выглядит так: под капотом:

<%= link_to number_to_human(volume.number), volume_path(volume), :remote => true %>

Это отправляет запрос javascript контроллеру, который выглядит следующим образом:

def show
  @volume = Volume.find(params[:id])

  respond_to do |format|
    format.html # show.html.erb
    format.js # show.js.erb
    format.json { render json: @volume }
  end
end

Это передает запрос show.js.erb, который выглядит следующим образом:

var stateObject = {"html": "<%= escape_javascript render(@volume) %>"};
history.pushState(stateObject,'',"<%= escape_javascript volume_path(@volume) %>");
$('#volumes').fadeTo(0, 0);
$('#volumes').html(stateObject.html).fadeTo('slow', 1.0);

Что затем заменяет содержимое тега div на исходной странице и использует pushState для создания объекта состояния и изменения URL-адреса страницы.

Затем пользователь может нажать кнопку "Назад" , а javascript, прикрепленный к событию window.onpopstate в show.html.erb, перезагрузит соответствующий контент:

    if(history.pushState) {
    window.onpopstate = function(event) {  
        if (event.state != null) {
            $('#volumes').html(event.state.html);
        }
    }
}

Ответы

Ответ 1

Я очень новичок в RoR, поэтому не уверен, что мой ответ будет лучшим, но я столкнулся с той же проблемой и смог ее исправить. Итак, вот мои два цента.

Кажется, что сырой ответ аякса происходит из-за кеша браузера. Я исправил проблему, добавив следующий заголовок, чтобы предотвратить ответ от кеширования.

response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"

Ответ 2

То, что Джун сказала выше, определенно сработало. Я просто добавил дополнительную проверку, чтобы проверить, был ли запрос из ajax, прежде чем я добавил заголовки. Спасибо, Joon!

if request.xhr?
    response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
    response.headers["Pragma"] = "no-cache"
    response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
end