jQuery ajax请求不会触发来自rails控制器的JS响应?

时间:2011-08-02 23:06:51

标签: ruby-on-rails ruby-on-rails-3 jquery

我有一个标准控制器,它被设置为响应HTML,JS和JSON请求:

def picture
  @picture = Picture.new params[:picture]

  respond_to do |format|
    if @picture.save
      format.html do
        logger.debug "In the HTML responder"
        redirect_to @picture
      end
      format.json { render json: @picture, status: :created, location: @picture }
      format.js { render :nothing => true }
    else
      # you get the idea
    end
  end
end

现在我正在尝试使用$.ajax函数向该控制器发送请求(在这种特定情况下我无法使用:remote => true - 我正在尝试使ajax文件上传工作)

$.ajax({
  url: $("form#new_picture").attr("action"),
  type: "POST",
  data: formdata,
  processData: false,
  contentType: false
});

问题是我的请求由于某种原因被视为HTML请求。我如何告诉rails我想要一个JS响应?

顺便说一下,我在我的项目中使用了jquery_ujs,所以如果有必要,我可以访问它提供的方法。我不是很擅长JS来调整那里做我需要的东西。

8 个答案:

答案 0 :(得分:50)

此解决方案对我不起作用(rails 3.1 + coffeescript)。在搜索了很多之后,我找到了做这件事的好方法,我想分享一下:

只需将“.js”添加到网址的末尾即可。这么简单......; - )

答案 1 :(得分:30)

只需添加dataType: 'script'

即可
$.ajax({
  url: $("form#new_picture").attr("action"),
  type: "POST",
  data: formdata,
  processData: false,
  contentType: false,
  dataType: 'script'
});    

答案 2 :(得分:6)

您必须在发送ajax请求之前设置'accept'标头,以便Rails知道如何响应。

$.ajax({
  url: $("form#new_picture").attr("action"),
  type: "POST",
  data: formdata,
  processData: false,
  contentType: false,
  beforeSend: function(xhr, settings) {
    xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
  }
});

答案 3 :(得分:5)

添加dataType: 'script'并在表单数据中添加参数format: 'js',如下所示:

$.ajax({
  url: '/manager/consumers/url',
  type: 'GET',
  dataType: 'script',
  data: {
  authenticity_token: '<%= form_authenticity_token %>',
  param_1: '1',
  param_2: '2',
  format: 'js'
  }
});

还在控制器中添加不渲染布局:

  respond_to do |format|
      format.xls 
      format.js { render :layout => false }
    end

答案 4 :(得分:3)

您可以检查它是否是xhr请求并呈现您喜欢的格式。例如;

if request.xhr?
  render :json => {
    :some_data => 'bla'
  }
end

答案 5 :(得分:3)

虽然可能没有直接回答这个问题,但我遇到了类似的问题,其他人可能会觉得这很有帮助。特别是如果你使用haml。

经过多次尝试(包括将.js附加到url)后,唯一对我有用的是在返回脚本响应时禁用布局渲染器。

  respond_to do |format|
    format.html
    format.js { render layout: false }
  end

我的问题是AJAX响应是由rails布局模板机制生成的完整html页面。这意味着我的thing.js.erb中的javascript并未执行。禁用布局意味着只返回了javascript(您可以在开发人员窗格的浏览器网络选项卡中找到返回),这样就可以执行它。

我使用haml作为我的默认渲染器,我相信这就是为什么我需要在js渲染中明确禁用布局(我原以为它会是自动的)。

因此,如果没有其他方法可以使用haml,请尝试使用。

答案 6 :(得分:3)

让我解释一下这里发生了什么。

我经常得到客户端在HTTP中混淆的服务器发送的Accept标头和Content-type Header。 Accept标头用于告诉服务器哪些内容类型(application / json,application / javascript,application / octet-stream,audio / mpeg,image / png,multipart / alternative,text / plain,text / html,text / csv ,video / mpeg等)他们会接受。服务器发回一个响应,其中包含Content-Type标头,通知客户端内容的实际内容类型。

HTTP请求也可以指定Content-Type,因为在表单数据中,可能存在所有类型的数据,并且Content-Type标头可以向服务器通知数据实际是什么(例如,multipart / form-data)。不同的媒体类型(如multipart / form-data)称为MIME。

现在jQuery.ajax()有另一个可以传递它的参数与这个主题相关:accepted,contentType,dataType。

如果您了解Content-Type HTTP标头,则contentType属性是明确的。它告诉服务器实际上是什么数据。 jQuery中的默认值为&#34; application / x-www-form-urlencoded; charset = UTF-8&#34;,这对大多数情况都适用。

请记住,Accept标头告诉服务器它将接受哪种Content-Type。但是,当您阅读dataType的jQuery文档时,它听起来非常相似:&#34;您期望从服务器返回的数据类型。&#34;那有什么区别?

accepted属性允许您更改请求中的Accept标头。但是通过更改dataType,它也会更改Accept标头,因此实际上不需要更改accept属性; dataType将更改Accept标头。 dataType的优点是ti允许您在成功处理程序可用之前预处理响应。

实际上,我们需要告诉Rails我们将接受什么作为响应头,因此我们修改了dataType。在Rails中,符号:js和:json,例如,对应于HTTP Mime类型:

Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript )
Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )

因此,如果我们想在respond_to块中触发:js选项,那么我们需要将jQuery中的dataType指定为脚本。正如其中一个答案所示,你这样做:

$.ajax({
  url: "users/populate_user,
  type: "POST",
  data: formdata,
  dataType: 'script'
});  

现在看看Request Header看起来多么漂亮了:

enter image description here

注意如何将dataType指定为脚本会将Accept标头更改为application / javascript。另请注意,contentType为&#34; application / x-www-form-urlencoded;字符集= UTF-8&#34 ;.记得我说如果没有指定,这是默认的Content-Type jQuery会使用吗?此SO页面中提供的另一个答案也指定了此选项:

  contentType: false

根据jQuery文档:

  

从jQuery 1.6开始,您可以传递false来告诉jQuery不设置任何内容   内容类型标题。

最后一点。在您的Rails控制器中,如果此控制器操作仅响应:js,则无需指定:js标志。您可以简单地省略控制器的respond_to:

  def populate_user
    @user = User.from_names(params[:name][:value]).first
  end

然后添加users / populate_user.js.erb文件。还要确保您的路线设置为发布请求:

post 'users/populate_user', to: 'users#populate_user'

从SO复制和粘贴答案时,了解您在项目中使用的内容也很重要。

答案 7 :(得分:0)

contentType设为"text/javascript"

$.ajax({
  url: $("form#new_picture").attr("action"),
  type: "POST",
  data: formdata,
  processData: false,
  contentType: "text/javascript"
});