Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails - form doesn't submit any data during AJAX call - file upload - 422 status code

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:

<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:

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.

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.

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: enter image description here

But data is NOT being send to the server: enter image description here

On the other hand in my second working project, data is being sent: enter image description here

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.

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.

like image 746
Giron Avatar asked Feb 10 '16 08:02

Giron


2 Answers

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:

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

after (working):

//= require bootsy
//= require bootsy/locales/cs.js
//= require jquery-fileupload
like image 128
Giron Avatar answered Oct 12 '22 20:10

Giron


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,

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'.

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.

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.

like image 35
B Seven Avatar answered Oct 12 '22 19:10

B Seven