3

I'm working through a Mongo/Node/Express example to help me understand how the pieces of a full-stack project fit together. The application is a pretty straightforward: an express server sends a page that the user can use to upload a picture. The pictures are saved and users can use the site to look through the uploaded pictures and see various stats.

I haven't started implementing anything related to persistence or Mongo, so I'm pretty sure that's not an issue (which means it probably is). I'm using these frameworks/packages:

Node.js: 0.10.33

  • Express: 4.10.7
  • Express-Handlebars: 1.1.0
  • MongoDB: 1.4.28
  • Mongoose: 3.8.21

Bower: 1.3.12

  • Bootstrap: 3.3.1

The error I can't figure out shows up when I try to upload an image file on the site. When I select an image file and hit 'submit,' I get the following error in the browser...

Connect

500 TypeError: Cannot read property 'file' of undefined
   at saveImage (/home/dan/development/tuts-book/controllers/image.js:47:37)
   at module.exports.create (/home/dan/development/tuts-book/controllers/image.js:66:9)
   at Layer.handle [as handle_request] (/home/dan/development/tuts-book/node_modules/express/lib/router/layer.js:82:5)
   at next (/home/dan/development/tuts-book/node_modules/express/lib/router/route.js:100:13)
   at Route.dispatch (/home/dan/development/tuts-book/node_modules/express/lib/router/route.js:81:3)
   at Layer.handle [as handle_request] (/home/dan/development/tuts-book/node_modules/express/lib/router/layer.js:82:5)
   at /home/dan/development/tuts-book/node_modules/express/lib/router/index.js:235:24
   at Function.proto.process_params (/home/dan/development/tuts-book/node_modules/express/lib/router/index.js:313:12)
   at /home/dan/development/tuts-book/node_modules/express/lib/router/index.js:229:12
   at Function.match_layer (/home/dan/development/tuts-book/node_modules/express/lib/router/index.js:296:3)

Here's the code I'm working with:

Package.json

{
  "name": "tuts-book",
  "version": "1.0.0",
  "description": "Working example from Web Development with MongoDB and Node.js.",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Dan Schatz",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.10.1",
    "cookie-parser": "^1.3.3",
    "errorhandler": "^1.3.2",
    "express": "^4.10.7",
    "express-handlebars": "^1.1.0",
    "method-override": "^2.3.1",
    "moment": "^2.9.0",
    "mongodb": "^1.4.28",
    "mongoose": "^3.8.21",
    "morgan": "^1.5.1"
  }
}

Server: server.js

'use strict';

var express = require('express'),
    config = require('./server/configure'),
    app = express();

app.set('port', process.env.PORT || 3300);
app.set('views', __dirname + '/views');

app = config(app);

var server = app.listen(app.get('port'), function() {
    console.log('Server up: http://localhost:' + app.get('port'));
});

Route File: routes.js

'use strict';

var home    = require('../controllers/home'),
    image   = require('../controllers/image');

module.exports.initialize = function(app, router) {

    router.get('/', home.index);
    router.get('/images/:image_id', image.index);

    router.post('/images', image.create);
    router.post('/images/:image_id/like', image.like);
    router.post('/images/image_id/comment', image.comment);

    app.use('/', router);
};

View Wrapper: main.handlebars

<!DOCTYPE HTML>

<html lang="eng">

    <head>
        <meta charset="UTF-8">

        <title>Tuts Book</title>
        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
        <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
        <link href="/public/css/styles.css" rel="stylesheet" type="text/css" >
    </head>

    <body>

        <div class="page-header">
            <div class="container">
                <div class="col-md-6">
                    <h1><a href="/">imgPloadr.io</a></h1>
                </div>
            </div>
        </div>

        <div class="container">
            <div class="row">

                <div class="col-sm-8">
                    {{{body}}}
                </div>

                <div class="col-sm-4">
                    {{> stats this }}

                    {{> popular this }}

                    {{> comments this }}
                </div>

            </div>
        </div>

        <div style="border-top: solid 1px #eee; padding-top: 1em;">
            <div class="container">
                <div class="row">
                    <div class="col-sm-12 text-center">
                        <p class="text-muted">Schatz.com | &copy; 2014</p>
                        <p class="text-center">
                            <i class="fa fa-twitter-square fa-2x text-primary"></i>
                            <i class="fa fa-facebook-square fa-2x text-primary"></i>
                        </p>
                    </div>
                </div>
            </div>
        </div>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
        <script src="/public/js/scripts.js" type="text/javascript" ></script>

    </body>
</html>

Index View: index.handlebars

<div class="panel panel-primary">

    <div class="panel-heading">
        <h2 class="panel-title">{{ image.title }}</h2>
    </div>

    <div class="panel-body">
        <p>{{ image.description }}</p>
        <div class="col-md-12 text-center">
            <img src="/public/upload/{{ image.filename }}" class="img-thumbnail">
        </div>
    </div>

    <div class="panel-footer">
        <div class="row">
            <div class="col-md-8">
                <button class="btn btn-success" id="btn-like" data-id="{{ image.uniqueId }}"><i
                        class="fa fa-heart"> Like</i></button>
                <strong class="likes-count">{{ image.likes }}</strong> &nbsp; - &nbsp; <i
                    class="fa fa-eye"></i> <strong>{{ image.views }}</strong>
                &nbsp; - &nbsp; Posted: <em class="text-muted">{{ timeago image.timestamp }}</em>
            </div>
        </div>
    </div>
</div>

<div class="panel panel-default">

    <div class="panel-heading">
        <div class="row">
            <div class="col-md-8">
                <strong class="panel-title">Comments</strong>
            </div>
            <div class="col-md-4 text-right">
                <button class="btn btn-default btn-sm" id="btn-comment" data-id="{{ image
                .uniqueId }}"><i class="fa fa-comments-o"> Post Comment...</i></button>
            </div>
        </div>
    </div>

    <div class="panel-body">
        <blockquote id="post-comment">
            <div class="row">

                <form method="post" action="/images/{{ image.uniqueId }}/comment">
                    <div class="form-group col-sm-12">
                        <label class="col-sm-2 control-label" for="name">Name:</label>
                        <div class="col-sm-10">
                            <input class="form-control" type="text" name="name">
                        </div>
                    </div>

                    <div class="form-group col-sm-12">
                        <label class="col-sm-2 control-label" for="email">Email:</label>
                        <div class="col-sm-10">
                            <input class="form-control" type="text" name="email">
                        </div>
                    </div>

                    <div class="form-group col-sm-12">
                        <label class="col-sm-2 control-label" for="comment">Comment:</label>
                        <div class="col-sm-10">
                            <textarea class="form-control" name="comment" rows="2"></textarea>
                        </div>
                    </div>

                    <div class="form-group col-sm-12">
                        <div class="col-sm-12 text-right">
                            <button type="submit" id="comment-btn" class="btn btn-success"
                                    type="button"><i class="fa fa-comment"></i> Post</button>
                        </div>
                    </div>
                </form>
            </div>
        </blockquote>

        <ul class="media-list">
            {{#each comments}}
            <li class="media">
                <a class="pull-left" href="#">
                    <img class="media-object img-circle" src="http://www.gravatar.com/avatar/{{
                    gravatar }}?d=monsterid&s=45">
                </a>
                <div class="media-body">
                    {{ comment }}
                    <br/><strong class="media-heading">{{ name }}</strong> <small
                        class="text-muted">{{ timeago timestamp }}</small>
                </div>
            </li>
            {{/each}}
        </ul>

    </div>
</div>

I've spent a couple days looking into a bunch of different possibilities (including new Express 4.0 stuff), but I've run out of leads.

I also found this post: req.files question, but I already have that solution in my HTML.

If you guys have any thoughts, I'd really appreciate the help. And if there's relevant code that I haven't included, let me know and I'll add it. Thanks again.

Community
  • 1
  • 1
Dan
  • 31
  • 3
  • 1
    Can i see your images controllers? Can you share your project with github or perhaps send me in my email? marcelo.franco.alves@gmail.com . If you send to my email, please send without the node modules . –  Jan 13 '15 at 01:51
  • Definitely. I'll throw it up on GitHub shortly. – Dan Jan 13 '15 at 01:55
  • 1
    i am waiting.. i just can help u if i see all the code. –  Jan 13 '15 at 01:56
  • 2
    I am thinking you might need a module like multer,having the full code would definitely. – Rahat Mahbub Jan 13 '15 at 01:59
  • The repo's at [link](https://github.com/DanSchatz/tuts-book). Thanks for taking a look. – Dan Jan 13 '15 at 02:19
  • 1
    Hi @Dan.. i'm sorry for the wait.. im going see your code now. –  Jan 13 '15 at 03:37
  • 2
    I believe @RahatMahbub is correct--it looks like you haven't set up your server to process multipart posts, and for Express 4 you'll need multer to do it. – Jorge Aranda Jan 13 '15 at 05:36
  • I see, I'll try to add that. I'll be back with results. – Dan Jan 14 '15 at 01:31
  • It looks like that's all I needed. I got it to upload, now I just need to play around with Multer to see what else it can do. Thanks, guys! Now it's time to try out persistence.... – Dan Jan 14 '15 at 04:57

1 Answers1

0

Express 4 cant handle multipart posts, you would need to use Multer or Busboy. Look up GridFS, as you need to save the pic to the mongo database, linked to the user, and be able to retrieve it later.

I personally would just another server for pic upload instead, so you just have to handle the link as text with your node.js - mongodb setup. Take a look at this, its explained step by step: https://devcenter.heroku.com/articles/s3-upload-node

CyborgFish
  • 356
  • 6
  • 13