Search code examples
node.jsmongodbmulter

image doesnt upload using multer


Ok so in my app I am trying to allow image uploading using multer. My app is built using node.js and my database is using mongodb. When I create an account and select an image for the avatar image, it creates the account but automatically uses the no-image.png file I have setup in case someone doesn't select an image. Here is the code... Any help will be awesome.

    // handle signup logic
    router.post("/register", function(req, res) {
      upload(req, res, function(err) {
        if(err){
          req.flash("error", err.message);
          return res.redirect("/register");
        }
        var newUser = new User({
          username: req.body.username,
          firstName: req.body.firstName,
          lastName: req.body.lastName,
          email: req.body.email,
          bio: req.body.bio
        });

        if(typeof req.file !== "undefined") {
          newUser.avatar = '/uploads/userImg/' + req.file.filename;
        } else {
          newUser.avatar = '/uploads/userImg/no-image.png';
        }
        console.log(newUser);
        if(req.body.adminCode === process.env.ADMINCODE) {
          newUser.isAdmin = true;
        }

        if(req.body.answer !== process.env.SECRET){
          req.flash("error", "answer the question");
          return res.redirect("back");
        } else {
          User.register(newUser, req.body.password, function(err, user){
            if(err){
              return res.render("register", {error: err.message});
            }
            passport.authenticate("local")(req, res, function(){
              req.flash("success", "Welcome to Let's Camp " + user.username);
              res.redirect("/campgrounds"); 
            }); 
          });
        }
      });
    });



    var multer = require("multer");
    var storage =   multer.diskStorage({
      destination: function(req, file, callback) {
        callback(null, './public/uploads/userImg');
       },
      filename: function(req, file, callback) {
        callback(null, Date.now() + file.originalname);
      }
    });
    var upload = multer({ storage : storage}).single('image');



<% include ./partials/header %>

    <div class="row">
        <div class="col-xs-8 col-xs-offset-2">
          <form action="/register" method="post">
            <h1 class="text-center">Sign Up</h1>
        </div>
        <div class="row">
          <div class="col-xs-4 col-xs-offset-2">
            <div class="form-group">
              <label for="firstName">First Name</label>
              <input id="firstName" class="form-control" type="text" name="firstName" placeholder="First Name*" required>
            </div>
          </div>
          <div class="col-xs-4 col-xs-offset-0">
            <div class="form-group">
              <label for="lastName">Last Name</label>
              <input id="lastName" class="form-control" type="text" name="lastName" placeholder="Last Name*" required>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-xs-4 col-xs-offset-2">
            <div class="form-group">
              <label for="email">Email</label>
              <input id="email" class="form-control" type="email" name="email" placeholder="Email*" required>
            </div>
          </div>
          <div class="col-xs-4 col-xs-offset-0">
            <div class="form-group">
              <label for="avatar">Avatar Image URL</label>
              <input id="avatar" class="form-control" type="file" name="avatar">
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-xs-4 col-xs-offset-2">
            <div class="form-group">
              <label for="username">Username</label>
              <input id="username" class="form-control" type="text" name="username" placeholder="Username*" required>
            </div>
          </div>
          <div class="col-xs-4 col-xs-offset-0">
            <div class="form-group">
              <label for="password">Password</label>
              <input id="password" class="form-control" type="password" name="password" placeholder="Password*" required>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-xs-8 col-xs-offset-2">
            <div class="form-group">
              <label for="bio">Bio</label>
              <textarea id="bio" class="form-control" type="bio" name="bio" rows="5" placeholder="Write a short description of yourself and what you enjoy about camping."></textarea>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-xs-4 col-xs-offset-2">
            <div class="form-group">
              <label for="adminCode">Admin Code</label>
              <input id="adminCode" class="form-control" type="text" name="adminCode" placeholder="Admin Code">
            </div>
          </div>
          <div class="col-xs-4 col-xs-offset-0">
            <div class="form-group">
              <label for="number">Enter: I Love Camping</label>
              <input id="number" class="form-control" type="text" name="answer" placeholder="Answer*" required>
            </div>
          </div>
        </div>
        <div class="row">
          <div class="col-xs-8 col-xs-offset-2">
            <div class="form-group">
              <button class="btn btn-lg btn-primary btn-block">Sign Up!</button>
            </div>
            <a href="/campgrounds">Go Back</a>
            </form>
          </div>
        </div>
        <div class="row">
            <div class="col-xs-12">
                <p class="text-center"><strong>*</strong> indicates a required field.</p>
            </div>
        </div>
      </div>

    <% include ./partials/footer %>

If I use enctype="multipart/form-data" I get an error for some reason but if I leave it off it completes but the image still doesnt upload. Just reverts to the no-image.png


Solution

  • If You want to post file You've to use entype="multipart/form-data":

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

    If You've other problems so fix that problem.

    from documentation :

    .single(fieldname)

    Accept a single file with the name fieldname. The single file will be stored in req.file.

    So create upload method like this and call it in Your router:

    var uploadAvatar = multer({ storage : storage}).single('avatar');
    

    or rename Your input file name="image" :

    <input id="avatar" class="form-control" type="file" name="image">