javascriptnode.jssails.jsimage-uploadingskipper

Sails.js file upload - destroying req.body and .upload() callback executing before upload is actually complete


I am building a website using Sails, a page of which contains a form. This form has multiple text inputs, and a file upload input for the user to upload an image. The information from all text inputs are stored in a Postgres database, and the image is uploaded using the .upload() function described in the sails docs here and converted to a data uri which is then stored in the same Postgres database and used to display the image on the site.

The file input is the third to last input on the page, and I noticed that two things were happening:

1) The text in the two inputs after the file input was not being passed through to the controller as part of req.body, as form inputs normally are.

2) No data uri was stored in the database for some images.

I created a new basic sails app with a form that allows you to upload an image and exactly the same thing happens here.

Upon testing I discovered that small images work fine, while larger images do not. The 'small' image I used was 66kb, while another 800kb image produced the same effects mentioned above.

The new sails app, in the callback to the .upload() function, res.views another page that simply displays the uploaded image. With the 800kb image and larger images, by the time the page was rendered, instead of displaying the uploaded image, it displayed a broken image. In the chrome dev console it gave a 404 error for the image link, but if I add a query to the end of the image url (i.e. make chrome think it's a different url so reload the same image), the image displays fine. From this I am guessing that the .upload() callback is being called before the image is actually finished uploading, and by the time I have reloaded the image it has finished uploading.

I can see in the request headers that the inputs after the file input are being sent, but doing console.log(req.body) in the controller only logs out the inputs placed before the file input in the form.

I am using sails v0.11.0, and the code I am using is as follows:

HTML form (index.ejs)

<h1>Image Upload Test</h1>

<form method="post" enctype="multipart/form-data" action="/submit">

  <div>
    <input type="text" name="firstInput">
  </div>

  <div>
    <input type="file" name="image">
  </div>

  <div>
    <input type="text" name="imageUploaded" value="false">
  </div>

  <div>
    <input type="hidden" name="test" value="hello!">
  </div>

  <button type="submit">Upload</button>

  <script type="text/javascript">
    $('input:file').change(function() {
      $('input[name=imageUploaded]').val('true')
    });
  </script>

</form>

config/routes.js

module.exports.routes = {

  '/': 'ImageController.show',
  '/submit': 'ImageController.create'

The controller (ImageController.js)

module.exports = {
    show: function(req, res) {
        res.view('index.ejs');
    },

    create: function(req, res) {

        var fileName = 'image' + Date.now() + '.jpg';

    req.file('image')
    .upload({saveAs: __dirname + '/../../assets/images/' + fileName}, function(err, uploadedFiles) {
      if (err) return res.serverError(err);

            console.log('file uploaded');
            console.log();
            console.log(req.body);

            res.view('uploadedImage', {fileName: fileName});

    });

    }

};

The page to display the uploaded image (uploadedImage.ejs)

<%if (typeof(fileName) !== 'undefined') {%>
  <a href="/">
    <img src="/images/<%=fileName%>" style="width:100%; height:100%;">
  </a>
<%}%>

Can anyone explain why this is happening and help me to fix it?

Thanks


Solution

  • As per sails file upload documentation, All the text fields must be uploaded before file field, otherwise they dont get passed to action. Sails documentation File Upload sails