Print Page

Tuesday, August 12, 2014

Ruby on Rails: Ajax upload form loses form params - debugging post mortem

Situation:
In a rails application I work on, I encountered a form that stopped submitting correctly after it had previously been working. It was a rarely used web form last used in production some months ago.

Fill in the form, submit, get back a validation error on a field that was filled in being blank.

Start investigating and find the params posted to the controller include the authentication token, but not any of the values filled in on the form.

The form is submitted via Ajax, using the Malsup jquery.form.js plugin to jQuery and includes a file input field.

The bug reproduces in both Firefox and Chrome. Looking at the post in Firebug and Chrome's Developer Tools shows a Request Payload of
[object FormData]&authenticity_token=our_auth_token_string

This I initially mistook as being an object that wasn't parsing in the tool for some reason, but when I added
puts "content_length: " + request.content_length.to_s puts "raw_post: " + request.raw_post.to_s
to the controller's create method I saw that it was literally receiving the form payload as the string "[object FormData]".

That is what cracked it open. I went to the old bit of JavaScript where we put the authenticity token in for Ajax requests:

  $(document).ajaxSend(function(event, request, settings) {
    if (settings.contentType === "application/json") return;
    if (typeof(AUTH_TOKEN) == "undefined") return;

    settings.data = settings.data || "";
    settings.data += (settings.data ? "&" : "") + "authenticity_token=" + encodeURIComponent(AUTH_TOKEN);
  });


And sure enough, we were expecting a string there, to which the authenticity token argument could be concatenated. Since it is now a formData object after updating the jQuery version from 1.7.x to current recently, the concatenation was casting it to the object as a string form that you tend to see first when alerting variable contents in debugging and the variable happens to hold an object. Rails only kept the parseable portion as params.

So that function needs revision to only add the authenticity token to settings.data if it is a string and it needs one. Off to write the Karma Jasmine test that should catch this and then fix it...

No comments:

Post a Comment