Моя основная цель
Приложение 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);
}
}
}