For the past two days, my Rails Assessment partner and I have been working on revamping our project, ArtMart, in order to complete the Rails and JavaScript assessment. One of the requirements is to create a new resource and render the response without a page refresh using our existing Rails API and Ajax.
At first, this seemed like a very simple task. Especially since most of the labs leading up to the assessment provide practice using Ajax. However, once I started to implement this functionality, I quickly ran into a problem neither of us had ever encountered before.
The Problem
How to upload form data, including a file, and submit it via Ajax while preventing the page refresh, and then render the created resource from the response.
In a previous lab, I learned how to take all the form data and serialize it using jQuery’s .serialize() function. Hence, my initial notion that adding the functionality would not be too challenging. Well, I was wrong.
The code I had looked something like this:
function attachFormListener() {
$( "form" ).on( "submit", function(e) {
e.preventDefault();
let url = $(this).attr('action');
let data = $(this).serialize();
$.ajax({
url: url,
type: 'POST',
data: data,
success: function(response) {
let artwork = new Artwork(response.artwork);
let html = artwork.renderHTML();
$('.artwork-new').html(html);
}
});
});
}
This worked for all regular form input fields, but not for the file input field. The Ajax was was working and posting to the right action, but params was missing a key piece of information: the actual image data.

Because of this, the transaction was being rolled back and the resource just wouldn’t get created.
Looking for answers on how to handle file submission via Ajax using Rails, it seemed to be a problem that would require some workarounds. I tried a few of them but was unsuccessful. By this point, I don’t think my brain was processing right anymore.
Okay, So What Worked?
Using the FormData API.
The
FormDatainterface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using theXMLHttpRequest.send()method. It uses the same format a form would use if the encoding type were set to"multipart/form-data".Source: Mozilla Developer Network
This was actually one of the first things I had tried. Until I learned from a classmate (thank you, Gordon) that I was simply using it wrong! The code was actually very close to what I tried, but I was missing two key pieces of the puzzle.
For everything to work, I had to set processData and contentType both to false inside of the Ajax call.
So this is what the working code looks like now:
function attachFormListener() {
$( "form" ).on( "submit", function(e) {
e.preventDefault();
let url = $(this).attr('action');
$.ajax({
url: url,
type: 'POST',
data: new FormData(this), // compile 'this form' into key/value pairs
processData: false,
contentType: false,
success: function(response) {
let artwork = new Artwork(response.artwork);
let html = artwork.renderHTML();
$('.artwork-new').html(html);
}
});
});
}
After submitting the form this way, now params looks like this:

So with that, Paperclip can do its job and the resource can be created as normal and finally sent back to the client as JSON.
Conclusion
What I thought would be a simple feature to add, turned out to be a lengthy process leading to what felt like hours wasted. I remember at one point I almost gave up, and thought of satisfying the requirement in another way. However, I just couldn’t leave it alone, and I’m glad that I didn’t.
Although the solution ended up being very simple, further adding to that feeling of wasting so much time, I choose to look at this as just another learning opportunity on my journey toward becoming a web developer.
