Create - inserting an image model

We already have the functionality in place in our create function to handle randomly naming and uploading an image file. Now, we need to save that information to MongoDB for the uploaded image.

Let's update the original saveImage function inside controllers/images.js:create and include the functionality to tie it into the database.

Our goal with the saveImage function is twofold. First, we want to make sure
that we never save an image with the same randomly generated filename as an already existing image to the database. Second, we want to ensure that we only insert the image into the database after it has been successfully uploaded, renamed, and saved to the filesystem. We are going to make two modifications to the existing code to achieve this.

The first modification is to wrap the bulk of the logic with find against the randomly generated filename, and if any documents are returned as a match from MongoDB, to start the process over and repeat this as many times as necessary until we achieve a truly unique filename. The code to perform the search is as follows:

Models.Image.find({ filename: imgUrl }, (err, images)=>{ 
if (images.length> 0) { 
saveImage(); 
    } else { 
        // do all the existing work... 
    } 
});

If an images array that is returned from find has a length greater than zero, it means at least one image was found to have the same filename as was generated with our random for loop. If that's the case, we want to call saveImage again, which will repeat the whole process (randomly generate a new name and perform a find on the database for that new name). We do this by previously defining the saveImage function as a variable, so that within the saveImage function itself, we can execute it again by calling the original variable as the function.

A function that calls itself is called a recursive function.

Originally, the last step of the create function was to redirect the visitor to the image's page within the callback that fired when the filesystem rename was finished. This is where we're going to want to create a new Mongoose image model. We should redirect only when the database server has finished saving the image (again relying on a callback function). Consider the following line in the original function: assuming no images were returned from find, it means we have generated a truly unique filename for our image and we are safe to rename the file and upload it to the server, as well as save a record to the database:

res.redirect('/images/${ imgUrl}'); 

Replace this with this new block of code:

var newImg = new Models.Image({
title: req.body.title,
description: req.body.description,
filename: imgUrl + ext
});
newImg.save((err, image) => {
console.log('Successfully inserted image: ' + image.filename);
res.redirect(`/images/${image.uniqueId}`);
});

Here, we create a brand new Image model and pass in the default values via its constructor. The title and description fields get set right from the values passed in via the HTML form using req.body and the form field names (.title and .description). The filename parameter is built the same way as when we originally we set its destination for renaming it, except we don't include the path and directory names, just the randomly generated filename and the image's original extension.

We call the model's .save() function (just as we did earlier, when we updated the image's views property in the index controller function). The save function accepts a second parameter in its callback, which will be the updated version of itself. Once the save is completed and the image has been inserted into the MongoDB database, we then redirect to the image's page. The reason the callback returns the updated version of itself is because MongoDB automatically includes additional information, such as _id.

As a review and sanity check, here is the complete code for the saveImage function in controllers/image.js:create, with the new lines of code clearly highlighted:

var saveImage = function() {
var possible = 'abcdefghijklmnopqrstuvwxyz0123456789',
imgUrl = '';
for (var i = 0; i < 6; i += 1) {
imgUrl += possible.charAt(Math.floor(Math.random() *
possible.length));
}
/* Start new code: */
// search for an image with the same filename by performing a find:
Models.Image.find({ filename: imgUrl }, (err, images) => {
if (images.length > 0) {
// if a matching image was found, try again (start over):
saveImage();
} else {
/* end new code:*/
var tempPath = req.files.file.path,
ext = path.extname(req.files.file.name).toLowerCase(),
targetPath = path.resolve(`./public/upload/${imgUrl}${ext}`);

if (ext === '.png' || ext === '.jpg' || ext === '.jpeg' || ext ===
'.gif') {
fs.rename(tempPath, targetPath, (err) => {
if (err) { throw err; }

/* Start new code: */
// create a new Image model, populate its details:
var newImg = new Models.Image({
title: req.body.title,
filename: imgUrl + ext,
description: req.body.description
});
// and save the new Image
newImg.save((err, image) => {
res.redirect(`/images/${image.uniqueId}`);
});
/* End new code: */
});
} else {
fs.unlink(tempPath, () => {
if (err) { throw err; }

res.json(500, { error: 'Only image files are allowed.' });
});
}
/* Start new code: */
}
});
/* End new code: */
};

saveImage();

Don't forget to initially execute saveImage() right after the function is defined; otherwise, nothing will happen!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.62.122