Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialMike Lundahl
13,510 PointsUsing MongoDB as a Session Store
Thanks for a great course so far...
I'm a bit stuck.. everything worked fine following all the steps up until I got to this stage. I'm getting the error message of:
"TypeError: Cannot set property 'userId' of undefined"
I've been trying to backtrack and look for a solution for a couple of days but just can't figure it out. Any advice for what it could be or where I should look?
Also as a side note. I also had the message of:
"WARNING: Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead"
that I solved by adding "mongoose.Promise = global.Promise;" right before the mongo connection.
Don't know when this course was recorder but might it be that features used in the videos are outdated? (having similar issues with the react basics course, but that's another discussion)
Thanks!
Mike Lundahl
13,510 PointsHi Seth,
Here's how the code looks like currently... I don't have the code from when it was working, however it worked fine storing the session to memory and not mongoDB.
app.js
var babel = require("babel-core");
var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var app = express();
//mongo connection
var dbConn = require('./routes/database');
var db = dbConn.db;
//Parse incoming requests
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false}));
//file loads
// fs.readdirSync(__dirname + '/models/').forEach(function(filename) {
// if (~filename.indexOf('.js')) require(__dirname + '/models/' + filename)
// });
//Include models
var User = require('./models/user')
//Include routes
var routes = require('./routes/index');
app.use('/', routes);
//serve static files from /static
app.use(express.static(__dirname + '/static'));
// use session for tracking logins
app.use(session({
secret: 'storm is awesome',
resave: true,
saveUninitialized: false,
store: new MongoStore({
mongooseConnection: db
})
}));
app.get('/', function(req, res) {
res.sendFile(__dirname + '/statics/html/register.html');
});
var server = app.listen(8080, function () {
console.log('server is running at http://localhost:' + server.address().port);
});
Database connection
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var MongoClient = require('mongodb').MongoClient;
var mongoose = require('mongoose');
var db;
var error;
var waiting = [];
mongoose.Promise = global.Promise;
//mongo connection
mongoose.connect("mongodb://localhost:27017/storm", function(err, database) {
error = err;
db = database;
waiting.forEach(function(callback) {
callback(err, database);
});
if(!err) {
console.log("We are connected to stormdb");
}
});
var db = mongoose.connection;
module.exports.db = db;
The middleware
// Mongo Session middleware
function loggedOut(req, res, next) {
if(req.session && req.session.userId) {
return res.redirect('/profile');
}
return next();
}
function loginRequired(req, res, next) {
if(req.session && req.session.userId) {
var err = new Error("You must be logged in to view this page.");
err.status = 403;
return next(err);
}
}
module.exports.loggedOut = loggedOut;
module.exports.loginRequired = loginRequired;
The model, user.js
// JavaScript Document
var mongoose = require('mongoose');
var bcryptjs = require('bcryptjs');
var UserSchema = new mongoose.Schema({
userName: {
type: String,
unique: true,
required: true,
trim: true
},
email: {
type: String,
unique: true,
required: true,
trim: true
},
firstName: {
type: String,
unique: true,
required: true,
trim: true
},
lastName: {
type: String,
unique: true,
required: true,
trim: true
},
password: {
type: String,
unique: true,
required: true
}
});
// authenticate input against database documents
UserSchema.statics.authenticate = function (email, password, callback) {
User.findOne({ email: email })
.exec(function (error, user) {
if (error) {
return callback(error);
} else if ( !user ) {
var err = new Error('User not found.');
err.status = 401;
return callback(err);
}
bcryptjs.compare(password, user.password, function (error, result) {
if (result === true) {
return callback(null, user);
} else {
return callback();
}
})
});
};
//hash password before saving to database
UserSchema.pre('save', function (next) {
var user = this;
bcryptjs.hash(user.password, 10, function (err, hash) {
if (err) {
return next(err);
}
user.password = hash;
next();
})
});
//User model
var User = mongoose.model('User', UserSchema);
module.exports = User;
Routes
// JavaScript Document
var express = require('express');
var router = express.Router();
var User = require('../models/user');
var path = require('path');
var mid = require('../middleware')
// GET / login
router.get('/login', mid.loggedOut, function(req, res, next) {
return res.sendFile(path.join(__dirname, '../statics' ,'/html', 'login.html'));
});
// POST / login
router.post('/login', function(req, res, next) {
if (req.body.email && req.body.password ) {
User.authenticate(req.body.email, req.body.password, function (error, user) {
if (error || !user) {
var err = new Error ('Wrong email or password!');
err.status = 401;
return next(err);
} else {
req.session.userId = user._id;
return res.redirect('/profile');
//return res.send('logged in!');
}
});
} else {
var err = new Error('Email and password are required!')
err.status = 401;
return next(err);
}
});
// GET / logout
router.get('/logout', function (req, res, next) {
if (req.session) {
//delete the session
req.session.destroy(function(err) {
if(err) {
return next(err);
} else {
return res.redirect('/');
}
})
}
})
// GET / profile
router.get('/profile', mid.loginRequired, function(req, res, next) {
User.findById(req.session.userId)
.exec(function (error, user) {
if (error) {
return next (error);
} else {
return res.sendFile(path.join(__dirname, '../statics', '/html', 'profile.html'));
}
})
});
And here's the package.js
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "./index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"start": "webpack-dev-server --progess --inline --hot"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.0",
"body-parser": "^1.15.2",
"connect-mongo": "^1.3.2",
"express": "^4.14.0",
"express-session": "^1.14.2",
"mongodb": "^2.2.15",
"mongoose": "^4.7.3",
"react": "^15.4.1",
"react-dom": "^15.4.1"
},
"devDependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"react-hot-loader": "^1.3.1",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2",
"webpack-node-externals": "^1.5.4"
}
}
1 Answer
Seth Kroger
56,413 PointsI think the issue is that you put the app.use() for the session middleware after your router instead of before it. Since the router will be executed first, the session data won't be available to it.
Mike Lundahl
13,510 PointsHuge thanks Seth! That worked!
Seth Kroger
56,413 PointsSeth Kroger
56,413 PointsPerhaps if you shared the relevant code (the file(s) you edited between working and not working) we could take a look? There could be an issue you're missing.