I'm trying to upload a csv file with ajax from Ember Js and read it in my Rails application. I've tried two different approaches. In the first one I tried to send the file from Ember like this:
submitImport() {
  var fd = new FormData();
  var file = this.get('files')[0];
  fd.append("csv_file", file);
  return this.get('authAjax')
    .request('/contacts/import/csv', {
      method: 'POST',
      processData: false,
      contentType: false,
      data: fd 
    });
}
but the problem is that I don't get the csv_file param in the rails application. The request.content_type is application/x-www-form-urlencoded and I need multipart form. I could use reques.raw_post but then I get something like this ------WebKitFormBoundarymgBynUffnPTUPW3l\r\nContent-Disposition: form-data; name=\"csv_file\"; filename=\"elevatr_import.csv\"\r\nContent-Type: text/csv\r\n\r\ngeorgica,[email protected]\nleo, [email protected]\ngigel, [email protected]\n\r\n------WebKitFormBoundarymgBynUffnPTUPW3l--\r\n and I would need to somehow parse this, and I don't really like this solution. 
The other approach was to send the file base64 encoded and then decode it from Rails. I've tried this:
`
submitImport() {
  var fd = new FormData();
  var file = this.get('files')[0];
  this.send('getBase64', file);
  var encoded_file = this.get('encoded_file');
  return this.get('authAjax')
    .request('/contacts/import/csv', {
      method: 'POST',
      data: { csv_file: encoded_file }
    });
},
getBase64(file) {
  var controller = this;
  var reader = new FileReader();
  reader.readAsDataURL(file);
  reader.onload = function () {
    controller.set('encoded_file', reader.result);
  };
}
But for some reason, the post request is submitted first and only after that the getBase64 method is called. Does anyone knows why is this happening or if I should use a different approach?
Thanks
FormData
To send using multipart/form-data, you have the right idea and are setting the correct options, but it's possible that authAjax or something else is setting options that are causing a conflict, resulting in a content-type of application/x-www-form-urlencoded.
// this should make a request with a content-type of multipart/form-data
$.ajax({
    url: 'upload/destination',
    type: 'POST',
    data: formDataObj,
    contentType: false,
    processData: false,
});
Base64
The reason your file is read after your request is made is that FileReader works asynchronously. To send as a base64 encoded string, you'll need to wait for the reader to complete before initiating your ajax request. You can do that by making your request after the onloadend event.
actions: {
  submitImport() {
    var file = this.get('files')[0];
    this.encodeAndSendFile(file);
  },
},
sendFile(base64File) {
  return this.get('authAjax')
  .request('/contacts/import/csv', {
    method: 'POST',
    data: { csv_file: encoded_file },
  });
},
encodeAndSend(file) {
  var controller = this;
  var reader = new FileReader();
  reader.onloadend = function () {
    controller.sendFile(reader.result);
  };
  reader.readAsDataURL(file);
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With