当使用后退按钮时,Rails 3.1返回原始Javascript代码

Sim*_*mon 19 javascript ajax jquery ruby-on-rails-3.1

我的基本目标

一个Rails应用程序,可以在使用HTML5维护浏览器的历史状态时通过Ajax加载新内容.我有一个在Heroku上运行的应用程序的超级基本版本.我还设置了一个公共GitHub存储库,以便更详细地查看下面提到的所有代码.

问题

我使用HTML5浏览器历史记录API成功实现了基本应用程序(有时我也使用History.js jQuery插件创建了一个版本).在用户单击非ajax链接然后点击后退按钮之前,一切正常.例如,如果用户单击了第2项,则应用程序会成功加载新内容并更改浏览器状态.如果他们点击后退按钮,它也会正确地重新加载以前的内容,并将浏览器状态更改为匹配.但是,如果用户随后浏览到另一个网页(互联网上的任何其他页面),然后单击其浏览器的后退按钮,则Rails应用程序将呈现原始javascript而不是原始页面.

一切正常,直到最后一步,当控制器开始从show.js.erb而不是show.html.erb返回原始javascript时.我已经尝试更改控制器中的几个设置,但我无法弄清楚具体是什么造成的.我知道如果我删除show.js.erb中的history.pushState调用,问题就会停止(尽管显然我失去了我首先寻找的所有浏览器历史记录功能).

有任何想法吗?

额外奖励:令人难以忍受的细节

这就是它的全部工作方式(我想!).

用户点击链接,看起来像这样:

<%= link_to number_to_human(volume.number), volume_path(volume), :remote => true %>
Run Code Online (Sandbox Code Playgroud)

这会向控制器发送一个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
Run Code Online (Sandbox Code Playgroud)

这会将请求传递给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);
Run Code Online (Sandbox Code Playgroud)

然后,它替换原始页面上div标签的内容,并使用pushState创建状态对象并更改页面URL.

然后,用户可以单击后退按钮,附加到show.html.erb中window.onpopstate事件的javascript将重新加载相应的内容:

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

小智 18

我对RoR很新,所以我不确定我的答案是否最好,但我遇到了同样的问题并设法修复它.所以这是我的两分钱.

似乎显示原始的ajax响应因浏览器缓存而发生.我通过添加以下标头来解决问题,以防止响应开始缓存.

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"
Run Code Online (Sandbox Code Playgroud)

  • 我尝试在过滤器之前在applications_controller中添加`response.headers ["Cache-Control"]`,但是当我从chrome的控制台看到标题时,它被设置为`must-revalidate,private,max-age = 0`并因此获取来自缓存的原始脚本. (2认同)

the*_*mer 12

Joon上面所说的绝对有效.在添加标题之前,我刚添加了额外的检查以查看请求是否来自ajax.谢谢你!

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
Run Code Online (Sandbox Code Playgroud)