Reputation: 370
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:
But data is NOT being send to the server:
On the other hand in my second working project, data is being sent:
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.
Upvotes: 9
Views: 1299
Reputation: 370
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
Upvotes: 2
Reputation: 11196
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 )
private
def post_params
params.require(:post).permit(:title, :content, :bootsy_image_gallery_id)
end
Upvotes: 0
Reputation: 1264
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.
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.
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.
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.
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.
These are my theories, I hope that help you!
UPDATE
If both of your projects are using Rails v4.2, maybe the one that works has set protect_from_forgery
like this:
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 with: :exception
The difference between them is the application behavior when a request is found to be unverified. See more here.
Upvotes: 0
Reputation: 45943
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.
Upvotes: 1
Reputation: 44
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.
Upvotes: 0
Reputation: 18647
the CRSF authentication issues are the cross site scripting issues.To overcome this issue, do either,
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
Upvotes: -1