jquery-ujs: Missing X-CSRF-Token Header on AJAX POST Request with File Upload

I’m trying to trace either some sort of conflict on my end (my app is rather complex, albeit not really JS-wise) or a bug in jquery-ujs which I have tentatively traced to the nonBlankFileInputs variable. (That is the bug seems to occur, if this if block is true: https://github.com/rails/jquery-ujs/blob/master/src/rails.js#L477)

Basically, I have a form that sends correct AJAX requests (correct meaning including the X-CSRF-Token header) as long as, and only as long as, its file input field left empty. As soon as a file input field is selected the header is no longer sent (and I think the request is also no longer handled via AJAX).

Some quirky things about this form that may be contributing to this bug are

  • I use the simple_form gem instead of the default form_for tags.
  • The form itself is loaded by AJAX due to user input, so it isn’t present on the page at load time, in case that is causing some event not to bind to it.
  • The form loads in a modal box javascript library (called bootbox) which has its own button design, so the way I ended up implementing the submit action is by placing a display: none submit button within the <form> tags and then triggering it with javascript from the bootbox code with $('div.bootbox div.bootbox-body').find('input[type=submit]').first().click();. This has worked perfectly so far though.

Any advice on how I can trace this problem further would be greatly appreciated.

About this issue

  • Original URL
  • State: open
  • Created 9 years ago
  • Comments: 21 (6 by maintainers)

Most upvoted comments

After reading this again very carefully, I see that @mvastola and mine’s proposed solution for jquery-ujs is the exact same. 👏 @mvastola

Workaround

FYI, this doesn’t resolve this issue, but one workaround I’ve discovered is to include a javascript plugin that enables support for POST XHR requests with file inputs.

For example, if the following javascripts are required (in order):

And then something the following code is run at page load:

$(document).on('ajax:aborted:file', 'form', function(event, nonBlankFileInputs) {
  $(this).fileupload();
  $(this).fileupload('send', {fileInput: nonBlankFileInputs});
  return false;
});

All POST requests marked as “remote” will be submitted via XHR requests, even if they have file inputs.

@rafaelfranca

rails/rails#22807 doesn’t have any replies yet, unfortunately, so I’m tempted to just submit a PR to this repo to implement the fix the way I mentioned above.

I know you said you think the fix belongs in actionview, but I’m wary of doing that since any implementation there would break fragment caching… Is there any reason why you don’t think the fix belongs in this gem?

@rafaelfranca I have created issue https://github.com/rails/rails/issues/22807 in the rails repo to ensure that whatever PR I write, the repo owner is prepared to merge it.

Please comment there and share your perspective.

@rafaelfranca so doing some more investigation into this, I seem to have figured out the source of the problem here.

I’m not sure if you’d like to reopen this issue or if I should make a new one (please advise), but this definitely seems to warrant further discussion/analysis… Basically, this problem seems to be a case of both the action_view gem and the jquery-ujs gems each thinking that the other is handling the inclusion of the authenticity token when there is a file field in a form is submitted via AJAX. (See https://github.com/rails/rails/blob/621ed494f573c4e37c1f7d37cc8741cc4c502827/actionview/lib/action_view/helpers/form_tag_helper.rb#L20 on lines 20, 31 and 38 for further details.)

According to the source code comments there, a simple workaround would be to set config.action_view.embed_authenticity_token_in_remote_forms = true, but it appears this is intentionally disabled by default (and presumably delegated to this gem by the Rails team) to allow for the fragment caching of forms.

Might I propose solving this conflict by catching submit events for AJAX POST forms with file uploads and creating/updating a hidden authenticity_token input field (from the token in the meta tags) before letting the submission through?

If that route is not chosen, I really think there should at least be better warnings/documentation for this situation, since, AFAIK, there is currently none whatsoever, neither in Rails nor in this gem. (By “warnings”, I mean that perhaps an error should be thrown in ActionView if a file_field in a form_for where :remote => true and !config.action_view.embed_authenticity_token_in_remote_forms. This raises the question though as to why this functionality can’t just be implemented.)

Please let me know if I should also be creating a concurrent issue in the Rails repository.