Rails - 表单在AJAX调用期间不提交任何数据 - 文件上传 - 422状态代码

时间:2022-09-25 15:51:28

I have encountered a problem when trying to upload files with bootsy gem, but the problem is not related to bootsy itself. Bootsy generates a form with a following definition:

我在尝试使用bootsy gem上传文件时遇到了问题,但问题与bootsy本身无关。 Bootsy生成一个具有以下定义的表单:

<form class="bootsy-upload-form form-inline" id="new_image" data-type="json" enctype="multipart/form-data" action="/bootsy/image_galleries/67/images" accept-charset="UTF-8" data-remote="true" method="post">
<input name="utf8" value="✓" type="hidden">
<input name="authenticity_token" id="authenticity_token" value="1pQMR5j33OKupMg4TSnQafLQx1BxzWjkP1KqTfZafqDRfGqwB8r2J4FzRE+dyuoHVOw/W0qd1FZ1JoJsJFThDQ==" type="hidden">
...

When I try to upload a file, this line is executed:

当我尝试上传文件时,执行以下行:

this.uploadInput.closest('form').submit();

I have added alert before it so I would see how the serialized data of the form looks like and all the fields are shown as expected (including authenticity token etc.):

我之前添加了警报,所以我会看到表单的序列化数据是如何显示的,所有字段都按预期显示(包括真实性标记等):

alert(this.uploadInput.closest('form').serialize());

When the form is submitted, no data is send during POST request, only headers, nothing is seen in browser inspector, nothing can be seen in log files of rails, it just looks like this:

提交表单时,在POST请求期间没有数据发送,只有标题,在浏览器检查器中看不到任何内容,在rails的日志文件中看不到任何内容,它只是如下所示:

Started POST "/bootsy/image_galleries/47/images" for ::1 at 2016-02-05 11:20:04 +0100
Processing by Bootsy::ImagesController#create as HTML
Parameters: {"image_gallery_id"=>"47"}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 0ms (ActiveRecord: 0.0ms)
FATAL -- : 
ActionController::InvalidAuthenticityToken - ActionController::InvalidAuthenticityToken:
_ actionpack (4.2.4) lib/action_controller/metal/request_forgery_protection.rb:181:in `handle_unverified_request'_

I have authenticity token generated in the form, I have the token in meta tag, everything looks fine, no error is thrown anywhere. I also tried to create sample app which is similar to my real project and it worked as expected, form normally submitted data - when I tried to compare HTML code and javascript events attached to both, they were almost similar expect a few parts because of other gems like ajax_pagination etc., but there were no parts, which should cause such a behavior.

我在表单中生成了真实性令牌,我在元标记中有令牌,一切看起来都很好,没有任何错误被抛出。我还尝试创建类似于我的真实项目的示例应用程序,它按预期工作,形成正常提交的数据 - 当我尝试比较HTML代码和附加到两者的javascript事件时,它们几乎相似,期望一些部分因为其他宝石像ajax_pagination等,但没有任何部分,这应该导致这样的行为。

I am using Rails 4.2.4, turbolinks are disabled using the attribute data-no-turbolink on body element, project uses bootstrap and contains JS libraries like jQuery, underscore, parsley, momentjs.

我正在使用Rails 4.2.4,使用body元素上的属性data-no-turbolink禁用turbolinks,项目使用bootstrap并包含JS库,如jQuery,下划线,欧芹,momentjs。

I would appreciate any thoughts, what could went wrong, why the form should not submit any data, where could be a problem. Thanks in advance for any tip.

我会感激任何想法,可能出错的原因,为什么表单不应提交任何数据,哪里可能是一个问题。提前感谢任何提示。

UPDATE: Just to clarify things, I have taken a picture of a state before sending using AJAX - this javascript is part of jquery_ujs = RoR adapter for jQuery. You can see, that data contains all the form fields before send: Rails  - 表单在AJAX调用期间不提交任何数据 - 文件上传 -  422状态代码

更新:为了澄清事情,我在使用AJAX发送之前拍摄了一个状态 - 这个javascript是jQuery的jquery_ujs = RoR适配器的一部分。您可以看到,该数据包含发送前的所有表单域:

But data is NOT being send to the server: Rails  - 表单在AJAX调用期间不提交任何数据 - 文件上传 -  422状态代码

但是数据不会发送到服务器:

On the other hand in my second working project, data is being sent: Rails  - 表单在AJAX调用期间不提交任何数据 - 文件上传 -  422状态代码

另一方面,在我的第二个工作项目中,正在发送数据:

UPDATE 2: Just a few more information, bootsy gem, which is responsible for creation of the form uses remotipart to attach files to the request. Still...I was debugging the javascript and was unable to identify the problem. Both projects have the same version of jquery and remotipart, also the same version of rails. Looks like this will stay a mystery.

更新2:更多信息,bootsy gem,负责创建表单使用remotipart将文件附加到请求。仍然......我正在调试javascript并且无法识别问题。这两个项目都有相同版本的jquery和remotipart,也是相同版本的rails。看起来这将是一个谜。

UPDATE 3: So I have almost resolved the issue - uploading is now working, it looks like it was a problem with order of javascript libraries. I'll post the result as soon as I pinpoint the exact issue - I'll reverse the changes and try to fix it again.

更新3:所以我几乎解决了这个问题 - 上传现在正在运行,看起来这是javascript库的顺序问题。我会在确定问题后立即发布结果 - 我将反转更改并尝试再次修复它。

6 个解决方案

#1


2  

The Issue was with an order of javascript libraries included in application.js. Bootsy was defined after jquery-fileupload. It seems, that Bootsy must be defined before it, with this setup, both works well. So state before:

问题在于application.js中包含的javascript库顺序。 Bootsy是在jquery-fileupload之后定义的。似乎Bootsy必须在它之前定义,通过这种设置,两者都运作良好。所以说:

//= require jquery-fileupload
//= require bootsy
//= require bootsy/locales/cs.js

after (working):

之后(工作):

//= require bootsy
//= require bootsy/locales/cs.js
//= require jquery-fileupload

#2


1  

It seems that the Authenticity Token is not being sent to the server as expected.

似乎真实性令牌没有按预期发送到服务器。

I would look at the Network requests tab in the browser and inspect the body of the post.

我会查看浏览器中的网络请求选项卡并检查帖子的正文。

I think setting processData to false is correct. According to the JQuery docs,

我认为将processData设置为false是正确的。根据JQuery文档,

By default, data passed in to the data option as an object (technically, anything other than a string) will be processed and transformed into a query string

默认情况下,作为对象传入数据选项的数据(技术上,除了字符串之外的任何东西)将被处理并转换为查询字符串

Also, you can add this in the controller before the check for the token:

此外,您可以在检查令牌之前在控制器中添加它:

before_filter { puts params }

I would not skip the Authenticity Token before filter.

我不会在过滤之前跳过真实性标记。

Also, in your image "But data is NOT being send to the server:", you are looking at the headers. The Authenticity Token is sent in the body.

此外,在您的图像“但数据未发送到服务器:”,您正在查看标题。真实性令牌在身体中发送。

I think the issue is the way the form is being encoded. You should not encode it. Set the Content Type to multipart/form-data. The Content Type is currently set to 'application/x-www-form-urlencoded'.

我认为问题在于表单的编码方式。你不应该编码它。将内容类型设置为multipart / form-data。内容类型目前设置为“application / x-www-form-urlencoded”。

The server is URL decoding the form, which is combining all the fields into one. That's why it doesn't find the Authenticity Token.

服务器是对表单进行URL解码,将所有字段合并为一个。这就是它没有找到真实性令牌的原因。

According to Sending multipart/formdata with jQuery.ajax, you should set contentType to false in the ajax request. Alternately, you can set it to multipart/form-data.

根据使用jQuery.ajax发送multipart / formdata,您应该在ajax请求中将contentType设置为false。或者,您可以将其设置为multipart / form-data。

#3


0  

By default the form only sends normal data.If you need to send image along with the post request you can use remotipart gem. It works great .I have used it myself.

默认情况下,表单只发送普通数据。如果您需要发送图像以及发布请求,您可以使用remotipart gem。它很棒。我自己用过它。

#4


0  

I have two theories, none of them has nothing to do with your form:

我有两个理论,其中没有一个与你的形式无关:

First theory:

第一理论:

With the update of your question, if you look closely, cookies doesn't contain _csrf_token. If _csrf_token is not passed then Rails will raise that error message.

随着您的问题的更新,如果仔细观察,cookie不包含_csrf_token。如果未传递_csrf_token,则Rails将引发该错误消息。

I can't see if your form is generating their own hidden field with this value. It may be that one of your projects do so and the other does't. You should check it out.

我无法看到您的表单是否使用此值生成自己的隐藏字段。可能是你的一个项目这样做而另一个没有。你应该检查一下。

If that was the problem, there are various solutions that you can find. One of it is to include [csfr_meta_tag] in HTML head of the view. Check this out for more details.

如果这是问题,您可以找到各种解决方案。其中之一是在视图的HTML头中包含[csfr_meta_tag]。查看更多详细信息。

Second theory:

第二个理论:

If you are performing a CORS request, your browser makes an additional OPTIONS request first just to check that you do have permission to access this resource.

如果您正在执行CORS请求,则浏览器会首先发出一个额外的OPTIONS请求,以检查您是否有权访问此资源。

Apparently, _session_id cannot be sent in CORS, unless you enable it. To do so, you need to handle the OPTIONS request. This is done by modifying Access-Control-Allow-Origin, Access-Control-Allow-Methods and Access-Control-Allow-Headers headers on controller before_filter and after_filter methods.

显然,除非启用,否则无法在CORS中发送_session_id。为此,您需要处理OPTIONS请求。这是通过在控制器before_filter和after_filter方法上修改Access-Control-Allow-Origin,Access-Control-Allow-Methods和Access-Control-Allow-Headers头来完成的。

Here lives a gist that shows an example of this (Forget the skip_before_filter line!). If you want to get more details of appointed headers values, check this resource out.

这里有一个要点,显示了一个例子(忘记skip_before_filter行!)。如果要获取指定标头值的更多详细信息,请检查此资源。

These are my theories, I hope that help you!

这些是我的理论,希望对你有所帮助!

UPDATE

UPDATE

If both of your projects are using Rails v4.2, maybe the one that works has set protect_from_forgery like this:

如果你的两个项目都在使用Rails v4.2,那么有效的项目可能会设置protect_from_forgery,如下所示:

protect_from_forgery
# OR maybe
protect_from_forgery with: :null_session

And the one that doesn't work has set protect_from_forgery like this:

并且那个不起作用的那个设置了protect_from_forgery,如下所示:

protect_from_forgery with: :exception

The difference between them is the application behavior when a request is found to be unverified. See more here.

它们之间的区别在于发现未经验证的请求时的应用程序行为。在这里查看更多。

#5


0  

Without seeing your actual code, we are left at guesses and shooting in the dark, however as obvious as this may seem, I assume you've followed all gem instructions? The install generator uses asset pipeline and sets up initializers etc. This seems rather obvious but did you make sure to do whitelist bootsy param on the model in the app that's not working? (as per https://github.com/volmer/bootsy )

在没有看到你的实际代码的情况下,我们在猜测中并在黑暗中拍摄,但是看起来很明显,我假设你已经遵循了所有的宝石指令?安装生成器使用资产管道并设置初始化程序等。这似乎相当明显,但你确保在应用程序中的模型上做白名单booty param不工作? (根据https://github.com/volmer/bootsy)

private

def post_params
  params.require(:post).permit(:title, :content, :bootsy_image_gallery_id)
end

#6


-1  

the CRSF authentication issues are the cross site scripting issues.To overcome this issue, do either,

CRSF身份验证问题是跨站点脚本问题。要解决此问题,请执行以下任一操作:

skip_before_action :verify_authenticity_token in your controller

or you can comment this line in application controller.

或者您可以在应用程序控制器中注释此行。

protect_from_forgery with: :exception  

Visit this link for more description on this

请访问此链接以获取更多相关信息

#1


2  

The Issue was with an order of javascript libraries included in application.js. Bootsy was defined after jquery-fileupload. It seems, that Bootsy must be defined before it, with this setup, both works well. So state before:

问题在于application.js中包含的javascript库顺序。 Bootsy是在jquery-fileupload之后定义的。似乎Bootsy必须在它之前定义,通过这种设置,两者都运作良好。所以说:

//= require jquery-fileupload
//= require bootsy
//= require bootsy/locales/cs.js

after (working):

之后(工作):

//= require bootsy
//= require bootsy/locales/cs.js
//= require jquery-fileupload

#2


1  

It seems that the Authenticity Token is not being sent to the server as expected.

似乎真实性令牌没有按预期发送到服务器。

I would look at the Network requests tab in the browser and inspect the body of the post.

我会查看浏览器中的网络请求选项卡并检查帖子的正文。

I think setting processData to false is correct. According to the JQuery docs,

我认为将processData设置为false是正确的。根据JQuery文档,

By default, data passed in to the data option as an object (technically, anything other than a string) will be processed and transformed into a query string

默认情况下,作为对象传入数据选项的数据(技术上,除了字符串之外的任何东西)将被处理并转换为查询字符串

Also, you can add this in the controller before the check for the token:

此外,您可以在检查令牌之前在控制器中添加它:

before_filter { puts params }

I would not skip the Authenticity Token before filter.

我不会在过滤之前跳过真实性标记。

Also, in your image "But data is NOT being send to the server:", you are looking at the headers. The Authenticity Token is sent in the body.

此外,在您的图像“但数据未发送到服务器:”,您正在查看标题。真实性令牌在身体中发送。

I think the issue is the way the form is being encoded. You should not encode it. Set the Content Type to multipart/form-data. The Content Type is currently set to 'application/x-www-form-urlencoded'.

我认为问题在于表单的编码方式。你不应该编码它。将内容类型设置为multipart / form-data。内容类型目前设置为“application / x-www-form-urlencoded”。

The server is URL decoding the form, which is combining all the fields into one. That's why it doesn't find the Authenticity Token.

服务器是对表单进行URL解码,将所有字段合并为一个。这就是它没有找到真实性令牌的原因。

According to Sending multipart/formdata with jQuery.ajax, you should set contentType to false in the ajax request. Alternately, you can set it to multipart/form-data.

根据使用jQuery.ajax发送multipart / formdata,您应该在ajax请求中将contentType设置为false。或者,您可以将其设置为multipart / form-data。

#3


0  

By default the form only sends normal data.If you need to send image along with the post request you can use remotipart gem. It works great .I have used it myself.

默认情况下,表单只发送普通数据。如果您需要发送图像以及发布请求,您可以使用remotipart gem。它很棒。我自己用过它。

#4


0  

I have two theories, none of them has nothing to do with your form:

我有两个理论,其中没有一个与你的形式无关:

First theory:

第一理论:

With the update of your question, if you look closely, cookies doesn't contain _csrf_token. If _csrf_token is not passed then Rails will raise that error message.

随着您的问题的更新,如果仔细观察,cookie不包含_csrf_token。如果未传递_csrf_token,则Rails将引发该错误消息。

I can't see if your form is generating their own hidden field with this value. It may be that one of your projects do so and the other does't. You should check it out.

我无法看到您的表单是否使用此值生成自己的隐藏字段。可能是你的一个项目这样做而另一个没有。你应该检查一下。

If that was the problem, there are various solutions that you can find. One of it is to include [csfr_meta_tag] in HTML head of the view. Check this out for more details.

如果这是问题,您可以找到各种解决方案。其中之一是在视图的HTML头中包含[csfr_meta_tag]。查看更多详细信息。

Second theory:

第二个理论:

If you are performing a CORS request, your browser makes an additional OPTIONS request first just to check that you do have permission to access this resource.

如果您正在执行CORS请求,则浏览器会首先发出一个额外的OPTIONS请求,以检查您是否有权访问此资源。

Apparently, _session_id cannot be sent in CORS, unless you enable it. To do so, you need to handle the OPTIONS request. This is done by modifying Access-Control-Allow-Origin, Access-Control-Allow-Methods and Access-Control-Allow-Headers headers on controller before_filter and after_filter methods.

显然,除非启用,否则无法在CORS中发送_session_id。为此,您需要处理OPTIONS请求。这是通过在控制器before_filter和after_filter方法上修改Access-Control-Allow-Origin,Access-Control-Allow-Methods和Access-Control-Allow-Headers头来完成的。

Here lives a gist that shows an example of this (Forget the skip_before_filter line!). If you want to get more details of appointed headers values, check this resource out.

这里有一个要点,显示了一个例子(忘记skip_before_filter行!)。如果要获取指定标头值的更多详细信息,请检查此资源。

These are my theories, I hope that help you!

这些是我的理论,希望对你有所帮助!

UPDATE

UPDATE

If both of your projects are using Rails v4.2, maybe the one that works has set protect_from_forgery like this:

如果你的两个项目都在使用Rails v4.2,那么有效的项目可能会设置protect_from_forgery,如下所示:

protect_from_forgery
# OR maybe
protect_from_forgery with: :null_session

And the one that doesn't work has set protect_from_forgery like this:

并且那个不起作用的那个设置了protect_from_forgery,如下所示:

protect_from_forgery with: :exception

The difference between them is the application behavior when a request is found to be unverified. See more here.

它们之间的区别在于发现未经验证的请求时的应用程序行为。在这里查看更多。

#5


0  

Without seeing your actual code, we are left at guesses and shooting in the dark, however as obvious as this may seem, I assume you've followed all gem instructions? The install generator uses asset pipeline and sets up initializers etc. This seems rather obvious but did you make sure to do whitelist bootsy param on the model in the app that's not working? (as per https://github.com/volmer/bootsy )

在没有看到你的实际代码的情况下,我们在猜测中并在黑暗中拍摄,但是看起来很明显,我假设你已经遵循了所有的宝石指令?安装生成器使用资产管道并设置初始化程序等。这似乎相当明显,但你确保在应用程序中的模型上做白名单booty param不工作? (根据https://github.com/volmer/bootsy)

private

def post_params
  params.require(:post).permit(:title, :content, :bootsy_image_gallery_id)
end

#6


-1  

the CRSF authentication issues are the cross site scripting issues.To overcome this issue, do either,

CRSF身份验证问题是跨站点脚本问题。要解决此问题,请执行以下任一操作:

skip_before_action :verify_authenticity_token in your controller

or you can comment this line in application controller.

或者您可以在应用程序控制器中注释此行。

protect_from_forgery with: :exception  

Visit this link for more description on this

请访问此链接以获取更多相关信息