Now it would be nice
if you could keep the extension of our file here.
And to achieve this,
we have to change the configuration here
and move away from just specifying the destination
to actually telling Multer in detail
how the uploaded file should be stored.
This can be done by not setting the destination here,
but instead the storage option.
Storage, unlike destination,
does not just want a path,
but instead a complete storage object
that contains detailed instructions about the path
and the filename.
For this, we can create a new constant here,
storageOption, for example, or storageConfig
and create one by using multer.diskStorage.
This is a method we can execute
which creates a new storage object as expected by Multer.
And now we pass an object to diskStorage,
so to this method.
And in this object, we can specify a destination key,
and we can specify a filename key.
Now destination wants a function as a value,
a function that will receive the incoming request,
the file, and a callback function that we have to execute
once we are done deriving a destination.
All three parameter values here will be provided by Multer,
because it will be Multer that's calling this function
whenever it is seeing an incoming file.
For filename, it's the same.
There, we also have to define a function
that gets the request,
the file that was parsed by Multer,
and a callback that we have to call
in our function code here
that basically returns the filename
we chose for the uploaded file back to Multer.
So calling these callbacks is important,
because with that, we'll pass the configuration chosen by us
back to Multer.
And this is around a couple of corners,
a bit tricky to wrap your head around,
but in the end, these are approaches that allow us
to provide our own logic for Multer
to have full control over the path and the filename.
For example, here for destination,
to tell Multer that we wanna store the file
in the images folder,
we execute this cb parameter value as a function
because it will be a function.
Multer will give us a function
for this third parameter value.
And to this function, we have to pass two values.
Multer expects two values on this function here.
The first value is a potential error we might have
if something went wrong with generating the destination,
in case we have some more complex logic
for deriving this destination.
Here, I'll just hard code the destination.
Hence, I won't have any error,
and therefore, you should pass null
as a first parameter value to this callback function,
which will hand the data back to Multer.
The second parameter value then is the destination path
where you wanna store your file,
and in my case, that's images.
Now that's the destination function,
and that's all we have to do here.
So here I'm not doing anything fancy,
I'm just setting the destination folder back to images,
what we also had before with the dest option.
Now the filename function
is why I chose this approach though,
because here we can now also call callback
to pass the filename we wanna use for the uploaded file
back to Multer so that we use our own filename
instead of the default one inferred by Multer
which is missing the extension as you'll see here.
Here, we still pass a first parameter value,
which could be a potential error
we faced while generating the filename,
but I don't have an error here,
and then we pass the filename as a second value.
This should now not be a hard-coded value,
but instead here I wanna use the original filename
and then add some random or pseudorandom value to it.
For this, we can use the file parameter value,
which we'll get here by Multer,
which will be that file that Multer parsed,
and get the originalname from that.
So now we would store the file with its originalname
in that folder, which is not what I want.
But now, in front of that,
I will actually concatenate another string,
a dash to be precise.
And in front of that dash,
I will actually use Date.now.
Date is this built-in class that's available in JavaScript.
And here, I'm not using it to generate a new date
based on the current timestamp.
Instead, now is a built in method
which we can call on the date class just like this,
which will give us the current date
as a number in milliseconds.
So milliseconds since the beginning of time,
which in JavaScript's world, was on January the 1st, 1970.
So this will be a large number,
then I add a dash,
and then the original filename.
And with that, I should have a pretty unique filename.
Theoretically, two users could submit the same filename
at exactly the same millisecond,
but here for this demo application, that won't happen.
So that is now my filename that should be used by Multer.
And with that, we got our own storage configuration,
which we'll pass as a value to this storage key here.
So that was a lot of talking,
but with that, we're now configuring Multer
to use our own unique filename
that does still have the extension though,
because originalname contains the original extension.
And therefore,
if I delete the file that was uploaded before,
but I keep the images folder,
and we save everything,
if we go back and add a new user again,
enter a username and then choose the file,
if I upload this, it seems to work.
And now, you will see here in my log
that this actually now is a filename
which does still have the extension.
And here in the images folder,
you also still see the extension.
So that's all working here.
And now, that was a lot of work,
but we now did have a look at how Multer can be configured.
And now, we are ensuring that the uploaded file
is being stored.
Now what's not being stored is the other data
and also not the path to the uploaded file,
and we'll need to do that though
to then use it on the starting page
to output our userData, including the image.
So that will be our next step,
saving the data in a database
so that we can then serve it in a second step.