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

我有一个标准的控制器,它被设置为响应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来调整我在这里做我需要的东西。

这个解决方案对我不起作用(rails 3.1 + coffeescript)。 经过相当多的搜索后,我找到了做这件事的好方法,我想分享:

只需将“.js”添加到url的末尾即可。 很简单… ;-)

只需添加dataType: 'script'

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

您必须在发送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); } }); 

添加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 

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

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

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

contentType设置为"text/javascript"

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

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

我经常得到客户端在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中的默认值是“application / x-www-form-urlencoded; charset = UTF-8”,这在大多数情况下都适用。

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

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

实际上,我们需要告诉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的外观如何美观:

在此处输入图像描述

注意如何将dataType指定为脚本将Accept标头更改为application / javascript。 另请注意,contentType是“application / x-www-form-urlencoded; charset = UTF-8”。 记得我说如果没有指定,这是默认的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复制和粘贴答案时,确切了解您在项目中使用的内容也很重要。