Reputation: 1329
I know that I can change the filename with multer by means of the storage object like following:
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, process.env.UPLOAD_DIR);
},
filename: (req, file, cb) => {
cb(null, 'bla.png');
}
});
const upload = multer({ storage: storage } );
My request, besides having the file, also contains some text attributes such as name: myPic.png
.
Is it possible to dynamically change the filename dependent on other request attributes or within the controller like following:
filename: (req, file, cb) => {
cb(null, `${req.body.name}.png`);
}
or
router.post('/upload', upload.single('pic'), myController.upload);
/* in controller */
upload = async (req: Request, res: Response) => {
try {
/* change the filename of multer here? */
} catch (err) {
winston.error(`Error while uploading: ${err.message}`);
winston.error(`Stack trace: ${err.stack}`);
sendJSONResponse(res, err, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Upvotes: 3
Views: 1669
Reputation: 5947
According to the multer documentation it does not have access to req.body
for other additional fields, if you test it it receives an undefined
value, then a not so perfect but functional solution is the following, once the file is uploaded you can rename it as follows.
Add the native class fs for access to files option
const fs = require('fs');
In diskStorage
configuration add the name you want, for example bla.png
var storage = multer.diskStorage({
destination: path.join('public/images/'),
filename: function ( req, file, cb ) {
cb(null, 'bla.png');
}
});
The form with the text field for the custom name
<form action="/upload" enctype="multipart/form-data" method="POST">
<input type="file" accept="image/*" name="photo" >
<br><!--here is the custom file name-->
<input type="text" name="file_name">
<br>
<button type="submit">Send</button>
</form>
Within the post path, once you have sent the file whose name will be bla.png, you can replace that name with the one in a field of the form by accessing req.body.field_name
router.post('/upload', upload.single('photo'), (req, res) => {
//Here change the file name bla.png for the new value in req.body.field_name + original ext of file
fs.renameSync(req.file.path, req.file.path.replace('bla.png',
req.body.field_name + path.extname(req.file.originalname)));
if(req.file) {
res.json(req.file);
}
else throw 'error';
});
Upvotes: 2
Reputation: 4956
Multer is the middleware which both populates req.body
AND stores the file.
Also, when it reaches the filename()
function, there is no guarantee that the text fields will be populated in req.body
because it depends on which order the client sends them in (see last note).
From what I see, you have two options:
1) Rename the uploaded file after the multer upload middleware does its thing and populates req.body
as well as req.file
. So in your controller upload middleware, you'd do something like:
if (req.file) {
fs.renameSync(req.file.path, req.file.destination + req.body.name);
}
2) Change the request body text field into a query parameter. Then, inside filename()
you can do a req.query.name
.
Con: Not a very RESTful design, but maybe that is not so important to you.
Upvotes: 1