在后退按钮点击呈现的原始javascript

时间:2012-10-04 15:34:19

标签: jquery ruby-on-rails ajax

我们的团队最近提出了一个最初的边缘案例问题,当用户从具有某种javascript渲染的页面(无论是Ajax,标签等)中单击浏览器的后退按钮时,将显示原始javascript。要重新创建,我们按照以下步骤操作:

  • 访问用户职位申请指数
  • 点击管理职位发布页面的按钮
  • 点击标签(使用bettertabs gem)
  • 点击浏览器的后退按钮

前面的步骤将显示:

(function() {

  $(".job_applications").html("<li class=\"job_posting_application\">\n
    ...
    ...
    ...
    ...
  );

}).call(this);

在一些命中或未命中的情况下,您不需要在返回上一页之前单击选项卡,但它仍然会呈现原始javascript。在一天结束时,似乎最后渲染的模板正在被缓存,这在浏览器的部分是正常的和预期的,但导致我认为是一个更大的问题。

Rails指南在Layouts and Rendering部分中说明,特别是关于模板的MIME类型:

  

默认情况下,Rails将使用MIME内容类型text / html(或者application / json,如果使用:json选项,或者application / xml用于:xml选项)提供渲染操作的结果)。

根据Rails默认值,我们的控制器的索引操作应该呈现我们的index.html.slim模板。但是,当在拖尾服务器日志的同时对该页面进行非远程调用(例如,直接导航到浏览器中的页面)时,我们注意到它实际呈现index.js.coffee。以下是我们的控制器操作,请注意我们没有明确响应html或js格式,因为我们可能应该考虑此页面中的重叠功能:

def index
  @company_id, @division_id, @job_posting_id = params[:company_id], params[:division_id], params[:job_posting_id]

  # API requests are made here to instantiate @job_posting, et al.,
  # but are not shown for brevity

  authorize! :manage, @job_posting

  @survey = @job_posting.survey
  @job_applications = @job_posting.job_applications(sort_column, sort_direction)
end

但是,根据此设置,{/ 1}} 基于Rails默认值进行渲染。添加index.html.slim块时,缓存似乎仍然有效,控制器可能不关心respond_to块的存在:

respond_to

即使明确地,虽然有点臭,告诉每种格式呈现不同的模板,但def index ... ... respond_to do |format| format.html format.js end end 模板似乎优先于js.coffee模板:

html.slim

在上面的情况下,直接导航到浏览器中的页面(换句话说,不进行远程Ajax调用),服务器日志将呈现def index ... ... respond_to do |format| format.html { render template: "users/job_posting_applications/index" } format.js { render template: "users/job_posting_applications/ajax" } end end ,即使Rails默认为html,除非另有说明

所有这些都说,以下是其他一些发现:

ajax.js.coffee

您可以参考上面显示的整个请求in this pastie

为什么它作为JSON处理超出了我的考虑,考虑到我们没有在此请求上提供任何JSON,并且没有针对此路由的默认格式Started GET "/users/companies/1/divisions/18/job_postings/349421/applications" for 127.0.0.1 at 2012-10-03 19:55:26 -0400 Processing by Users::JobPostingApplicationsController#index as JSON 的路由规范。

此外,在此操作中调试:json的值时,它会返回request.format

提供的另一个方案是在另一个仅包含application/json模板的控制器(users/company_admin_metrics#index)内。导航到此页面时,服务器日志显示它在index.html.slim内呈现users/company_admin_metrics/index.html.slim。当我创建一个空白的js.coffee模板时:

layouts/users

并直接导航到该索引页面,服务器日志显示它呈现$ touch app/views/users/company_admin_metrics/index.js.coffee ,这进一步暴露了有关模板呈现优先级的潜在问题。

是否有人遇到类似的问题可能会为此提供潜在的解决方法?

我们的筹码

以下是这个特定问题的基本参与者的一小部分清单:

  • Rails 3.2.6
  • Coffee-Rails 3.2.1
  • Bettertabs 1.2.6

此请求取决于通过解析JSON并返回Ruby对象的客户端gem对我们的作业发布API的请求,但这些请求不会与此特定应用程序耦合,从而导致 this app为上述请求提供内容类型users/company_admin_metrics/index.js.coffee

3 个答案:

答案 0 :(得分:9)

我认为您需要将格式扩展名.js附加到您的ajax请求中的网址。

可能发生的情况是,用户正在index点击/job_applications操作并发出GET html请求。然后ajax正在点击相同的URL /动作但请求javascript。当用户单击后退按钮时,浏览器无法区分两者之间的差异,因此使用最新的(javascript响应)。

答案 1 :(得分:4)

自问这个问题以来已经有好几个月了,但是自从遇到这个问题以后,我就开始给我两分钱。

正如carbo所说,浏览器可以告诉html和js请求之间的区别,所以当单击后退按钮时,它会看到相同的url,只是提供了js代码中发生的缓存数据。我有一些问题,但使用推送状态javascript修改ajax请求的浏览器历史记录。我发现最简单的解决方案是告诉浏览器不要缓存请求。因此,当回到上一页时,它被迫重新加载它。

您可以全局禁用缓存: $ .ajaxSetup({cache:false});

或者您可以尝试在特定的ajax请求上指定缓存false。

答案 2 :(得分:4)

最近在使用Rails 4.2.4的Chrome中开始看到这个问题。似乎是一个众所周知且备受争议的问题。我们的团队通过向Vary次请求添加xhr标头来解决此问题:

class ApplicationController < ActionController::Base
  after_action :set_vary_header

  private

  # Fix a bug/issue/by-design(?) of browsers that have a hard time understanding
  # what to do about our ajax search page. This header tells browsers to not cache
  # the current contents of the page because previously when someone filtered results,
  # went to the listing's external site, then hit Back, they'd only see the last
  # ajax response snippet, not the full listings page for their search.
  #
  # Heated multi-year discussion on this issue in Chrome
  # https://code.google.com/p/chromium/issues/detail?id=94369
  #
  # And continued by the Rails team:
  # https://github.com/rails/jquery-ujs/issues/318
  # https://github.com/rails/jquery-rails/issues/121
  def set_vary_header
    if request.xhr?
      response.headers["Vary"] = "accept"
    end
  end
end