jQuery ajax请求没有从rails控制器触发JS响应?

时间:2022-10-08 22:52:13

I have a standard controller which is set up to respond to HTML, JS and JSON requests:

我有一个用于响应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

Now I'm trying to send a request to that controller with the $.ajax function (I can't use :remote => true in this specific situation - I'm trying to make ajax file upload work).

现在我尝试用$发送一个请求给那个控制器。ajax函数(我不能使用:remote =>在这个特定的情况下是真的-我正在尝试让ajax文件上载工作)。

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

The problem is that my request is being treated as a HTML request for some reason. How do I tell rails that I want a JS response?

问题是出于某种原因,我的请求被当作HTML请求来处理。我如何告诉rails我想要一个JS响应?

By the way, I'm using jquery_ujs in my project so I have access to the methods it provides if necessary. I'm not really good enough at JS to tweak that to do what I need here.

顺便说一下,我在我的项目中使用jquery_ujs,所以如果需要的话,我可以访问它提供的方法。我在JS方面还不够好,无法调整它来完成这里需要的工作。

8 个解决方案

#1


42  

This solution didn't work for me (rails 3.1 + coffeescript). After searching quite a lot, I found the good way to do it and I wanted to share:

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

Just add ".js" to the end of the url. So simple... ;-)

只是添加”。到url的末尾。这么简单……:-)

#2


30  

Just add dataType: 'script'

把数据类型:“脚本”

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

#3


6  

You have to set the 'accept' header before sending the ajax request so that Rails knows how to respond.

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

#4


5  

Add dataType: 'script' and in data of form add the parameter format: 'js' like this:

添加数据类型:'script',在表单数据中添加参数格式:'js'如下:

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

also add in the controller to not render layout:

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

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

#5


3  

You can check whether it is a xhr request and render the format you prefer. For Example;

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

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

#6


1  

Although possibly not directly answering the question, I came across this with a similar problem and others may find this helpful. Especially if you use haml.

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

After many attempts (including appending .js to the url) the only thing that worked for me was disabling the layout renderer when returning a script response.

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

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

My problem was that the AJAX response was a full html page generated by the rails layout template mechanism. This meant my javascript in my thing.js.erb wasn't executing. Disabling the layout meant only the javascript was returned (you can find the return in you browsers network tab of the developer pane) which allowed it to be executed.

我的问题是AJAX响应是rails布局模板机制生成的完整html页面。这意味着javascript在我的东西。js中。erb不执行。禁用布局意味着只返回javascript(您可以在developer窗格的浏览器网络选项卡中找到返回),从而允许执行它。

I'm using haml as my default renderer and I believe that is why I required explicitly disabling the layout in js renders (I had assumed it would be automatic).

我使用haml作为默认的渲染器,我认为这就是为什么我需要显式地禁用js渲染的布局(我假设它是自动的)。

So if nothing else has worked and you use haml, try this.

所以,如果没有其他有效的方法,你可以使用haml,试试这个。

#7


0  

Set contentType as "text/javascript"

contentType设置为“text / javascript”

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

#8


0  

Let me explain what is going on here.

我来解释一下。

I often get the Accept header and Content-type Header that a client sends to the server confused in HTTP. The Accept header is used to tell the server what content types (application/json, application/javascript, application/octet-stream, audio/mpeg, image/png, multipart/alternative, text/plain, text/html, text/csv, video/mpeg, etc) they'll accept. The server sends back a response, which includes the Content-Type header notifying the client of the actual Content Type of the content.

我经常收到客户端发送给服务器的Accept标头和Content-type标头,这些标头在HTTP中是混淆的。Accept标头用于告诉服务器他们将接受哪些内容类型(应用/json、应用/javascript、应用/octet-stream、音频/mpeg、图像/png、多部分/替代、文本/纯文本/html、文本/csv、视频/mpeg等)。服务器返回一个响应,其中包括通知客户端内容的实际内容类型的内容头。

HTTP requests can also specify Content-Type, because in form data, there could be all types of data, and the Content-Type header can notify the server what the data actually is (e.g. multipart/form-data). The different media types like multipart/form-data are known as MIME.

HTTP请求也可以指定内容类型,因为在表单数据中,可以有各种类型的数据,而Content-Type头可以通知服务器数据实际上是什么(例如多部分/表单数据)。不同的媒体类型(如多部分/表单数据)称为MIME。

Now jQuery.ajax() has another of parameters you can pass it related to this topic: accepts, contentType, dataType.

现在,jQuery.ajax()有另一个参数,您可以将它与这个主题相关:accept、contentType、dataType。

The contentType attribute is clear if you understand the Content-Type HTTP header. It tells the server what the data actually is. The default in jQuery is "application/x-www-form-urlencoded; charset=UTF-8", which is fine for most cases.

如果您理解内容类型的HTTP头,则contentType属性是清楚的。它告诉服务器数据实际上是什么。jQuery的默认值是“应用程序/x-www-form-urlencode;charset=UTF-8,这对大多数情况来说都很好。

Remember that the Accept header tells the server what Content-Type it will accept. But when you read the jQuery documentation for dataType, it sounds quite similar: "The type of data that you're expecting back from the server." So what is the difference?

请记住,Accept标头告诉服务器它将接受什么内容类型。但是当您阅读关于数据类型的jQuery文档时,它听起来非常相似:“您期望从服务器返回的数据类型。”有什么区别呢?

The accepts attribute allows you to change the Accept header in the request. But by changing the dataType it will change the Accept header too, so there is really no need to change the accept attribute; the dataType will change the Accept header. The benefit of dataType is ti allows you to pre-process the response before being available to the succes handler.

Accept属性允许您在请求中更改Accept标头。但是通过更改数据类型,它也将更改Accept标头,因此实际上不需要更改Accept属性;数据类型将更改Accept标头。数据类型的好处是允许您在对succes处理程序可用之前对响应进行预处理。

In effect, we need to tell Rails what we will accept as a response header, so we modify the dataType. In Rails the symbols :js and :json, for example, correspond to a HTTP Mime Type:

实际上,我们需要告诉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 )

Thus, if we want to trigger the :js option in the respond_to block, then we need to specify the dataType in jQuery as script. And as one of the answers illustrates, you do it like this:

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

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

Now look how beautiful the Request Header looks:

现在看看请求头看起来多么漂亮:

jQuery ajax请求没有从rails控制器触发JS响应?

Notice how specifying the dataType as script changed the Accept header to application/javascript. Also notice that the contentType is "application/x-www-form-urlencoded; charset=UTF-8". Remember I said this is the default Content-Type jQuery will use if none is specified? Well another answer provided in this SO page specified this option as well:

注意,如何将数据类型指定为脚本,从而将Accept标头更改为application/javascript。还要注意,内容类型是“application/ www-form- urlencoding”;charset = utf - 8”。还记得我说过,如果没有指定内容类型,jQuery将使用默认的内容类型吗?另一个答案在这个页面中也给出了这个选项

  contentType: false

According to the jQuery documentation:

根据jQuery文档:

As of jQuery 1.6 you can pass false to tell jQuery to not set any content type header.

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

One last point. In your Rails controller, you do not need to specify the :js flag if this controller action is only ever going to be responding to :js. You can simply omit the respond_to from the controller:

最后一个点。在Rails控制器中,如果这个控制器动作只会对:js做出响应,则不需要指定:js标志。您可以简单地从控制器中省略respond_to:

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

And then add a users/populate_user.js.erb file. Also make sure your route is set up for a post request:

然后添加user /populate_user.js。erb文件。还要确保你的路线是为一个post请求设置的:

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

When copying and pasting answers from SO, it is also important to understand exactly what you are using in your project.

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

#1


42  

This solution didn't work for me (rails 3.1 + coffeescript). After searching quite a lot, I found the good way to do it and I wanted to share:

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

Just add ".js" to the end of the url. So simple... ;-)

只是添加”。到url的末尾。这么简单……:-)

#2


30  

Just add dataType: 'script'

把数据类型:“脚本”

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

#3


6  

You have to set the 'accept' header before sending the ajax request so that Rails knows how to respond.

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

#4


5  

Add dataType: 'script' and in data of form add the parameter format: 'js' like this:

添加数据类型:'script',在表单数据中添加参数格式:'js'如下:

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

also add in the controller to not render layout:

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

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

#5


3  

You can check whether it is a xhr request and render the format you prefer. For Example;

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

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

#6


1  

Although possibly not directly answering the question, I came across this with a similar problem and others may find this helpful. Especially if you use haml.

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

After many attempts (including appending .js to the url) the only thing that worked for me was disabling the layout renderer when returning a script response.

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

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

My problem was that the AJAX response was a full html page generated by the rails layout template mechanism. This meant my javascript in my thing.js.erb wasn't executing. Disabling the layout meant only the javascript was returned (you can find the return in you browsers network tab of the developer pane) which allowed it to be executed.

我的问题是AJAX响应是rails布局模板机制生成的完整html页面。这意味着javascript在我的东西。js中。erb不执行。禁用布局意味着只返回javascript(您可以在developer窗格的浏览器网络选项卡中找到返回),从而允许执行它。

I'm using haml as my default renderer and I believe that is why I required explicitly disabling the layout in js renders (I had assumed it would be automatic).

我使用haml作为默认的渲染器,我认为这就是为什么我需要显式地禁用js渲染的布局(我假设它是自动的)。

So if nothing else has worked and you use haml, try this.

所以,如果没有其他有效的方法,你可以使用haml,试试这个。

#7


0  

Set contentType as "text/javascript"

contentType设置为“text / javascript”

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

#8


0  

Let me explain what is going on here.

我来解释一下。

I often get the Accept header and Content-type Header that a client sends to the server confused in HTTP. The Accept header is used to tell the server what content types (application/json, application/javascript, application/octet-stream, audio/mpeg, image/png, multipart/alternative, text/plain, text/html, text/csv, video/mpeg, etc) they'll accept. The server sends back a response, which includes the Content-Type header notifying the client of the actual Content Type of the content.

我经常收到客户端发送给服务器的Accept标头和Content-type标头,这些标头在HTTP中是混淆的。Accept标头用于告诉服务器他们将接受哪些内容类型(应用/json、应用/javascript、应用/octet-stream、音频/mpeg、图像/png、多部分/替代、文本/纯文本/html、文本/csv、视频/mpeg等)。服务器返回一个响应,其中包括通知客户端内容的实际内容类型的内容头。

HTTP requests can also specify Content-Type, because in form data, there could be all types of data, and the Content-Type header can notify the server what the data actually is (e.g. multipart/form-data). The different media types like multipart/form-data are known as MIME.

HTTP请求也可以指定内容类型,因为在表单数据中,可以有各种类型的数据,而Content-Type头可以通知服务器数据实际上是什么(例如多部分/表单数据)。不同的媒体类型(如多部分/表单数据)称为MIME。

Now jQuery.ajax() has another of parameters you can pass it related to this topic: accepts, contentType, dataType.

现在,jQuery.ajax()有另一个参数,您可以将它与这个主题相关:accept、contentType、dataType。

The contentType attribute is clear if you understand the Content-Type HTTP header. It tells the server what the data actually is. The default in jQuery is "application/x-www-form-urlencoded; charset=UTF-8", which is fine for most cases.

如果您理解内容类型的HTTP头,则contentType属性是清楚的。它告诉服务器数据实际上是什么。jQuery的默认值是“应用程序/x-www-form-urlencode;charset=UTF-8,这对大多数情况来说都很好。

Remember that the Accept header tells the server what Content-Type it will accept. But when you read the jQuery documentation for dataType, it sounds quite similar: "The type of data that you're expecting back from the server." So what is the difference?

请记住,Accept标头告诉服务器它将接受什么内容类型。但是当您阅读关于数据类型的jQuery文档时,它听起来非常相似:“您期望从服务器返回的数据类型。”有什么区别呢?

The accepts attribute allows you to change the Accept header in the request. But by changing the dataType it will change the Accept header too, so there is really no need to change the accept attribute; the dataType will change the Accept header. The benefit of dataType is ti allows you to pre-process the response before being available to the succes handler.

Accept属性允许您在请求中更改Accept标头。但是通过更改数据类型,它也将更改Accept标头,因此实际上不需要更改Accept属性;数据类型将更改Accept标头。数据类型的好处是允许您在对succes处理程序可用之前对响应进行预处理。

In effect, we need to tell Rails what we will accept as a response header, so we modify the dataType. In Rails the symbols :js and :json, for example, correspond to a HTTP Mime Type:

实际上,我们需要告诉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 )

Thus, if we want to trigger the :js option in the respond_to block, then we need to specify the dataType in jQuery as script. And as one of the answers illustrates, you do it like this:

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

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

Now look how beautiful the Request Header looks:

现在看看请求头看起来多么漂亮:

jQuery ajax请求没有从rails控制器触发JS响应?

Notice how specifying the dataType as script changed the Accept header to application/javascript. Also notice that the contentType is "application/x-www-form-urlencoded; charset=UTF-8". Remember I said this is the default Content-Type jQuery will use if none is specified? Well another answer provided in this SO page specified this option as well:

注意,如何将数据类型指定为脚本,从而将Accept标头更改为application/javascript。还要注意,内容类型是“application/ www-form- urlencoding”;charset = utf - 8”。还记得我说过,如果没有指定内容类型,jQuery将使用默认的内容类型吗?另一个答案在这个页面中也给出了这个选项

  contentType: false

According to the jQuery documentation:

根据jQuery文档:

As of jQuery 1.6 you can pass false to tell jQuery to not set any content type header.

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

One last point. In your Rails controller, you do not need to specify the :js flag if this controller action is only ever going to be responding to :js. You can simply omit the respond_to from the controller:

最后一个点。在Rails控制器中,如果这个控制器动作只会对:js做出响应,则不需要指定:js标志。您可以简单地从控制器中省略respond_to:

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

And then add a users/populate_user.js.erb file. Also make sure your route is set up for a post request:

然后添加user /populate_user.js。erb文件。还要确保你的路线是为一个post请求设置的:

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

When copying and pasting answers from SO, it is also important to understand exactly what you are using in your project.

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