I'm using making error messages available on res.locals and displaying them as needed with a redirect. I am not completely sure how this works, but it does. At least when I'm running the server locally.
Deployed to Heroku on the other hand, it doesn't. There's nothing. I make mistakes on the page and my sexy flash messages are glimmering with their absence.
I'm using sqlite3 locally and storing sessions with connect-session-sequelize
.
I'm using postgres on Heroku.
server.js
/* jshint node: true */
'use strict';
var express = require('express');
var session = require('express-session');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var _ = require('underscore');
var db = require('./db.js');
var SequelizeStore = require('connect-session-sequelize')(session.Store);
var flash = require('express-flash');
var app = express();
var PORT = process.env.PORT || 3000;
app.use(cookieParser());
// Track logins with express session
app.use(session({
secret: 'Magic mike',
resave: true,
saveUninitialized: false,
store: new SequelizeStore({
db: db.sequelize
})
}));
app.use(flash());
// Make userId available in templates
app.use(function(req, res, next){
res.locals.currentUser = req.session.userId;
res.locals.sessionFlash = req.session.sessionFlash;
delete req.session.sessionFlash;
next();
});
// To parse incoming req
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
// Serve static files
app.use(express.static(__dirname + '/public'));
// View engine setup
app.set('view_engine', 'pug');
app.set('views', __dirname + '/views');
var routes = require('./routes/index.js');
app.use('/', routes);
....
db.js
var Sequelize = require('sequelize');
var env = process.env.NODE_ENV || 'development';
var sequelize;
if (env === 'production') {
sequelize = new Sequelize(process.env.DATABASE_URL, {
dialect: 'postgres'
});
} else {
sequelize = new Sequelize(undefined, undefined, undefined, {
'dialect': 'sqlite',
'storage': __dirname + '/data/shoplist.sqlite'
});
}
var db = {};
db.item = sequelize.import(__dirname + '/models/item.js');
db.user = sequelize.import(__dirname + '/models/user.js');
// db.shoplist = sequelize.import(__dirname + '/models/shoplist.js');
db.sequelize = sequelize;
db.Sequelize = Sequelize;
// db.item.belongsTo(db.shoplist);
// db.shoplist.hasMany(db.item);
db.item.belongsTo(db.user);
db.user.hasMany(db.item);
// db.user.belongsTo(db.shoplist);
// db.shoplist.hasMany(db.user);
module.exports = db;
....
routes/index.js
var express = require('express');
var router = express.Router();
var _ = require('underscore');
var mid = require('../middleware/');
var db = require('../db.js');
var flash = require('express-flash');
router.all('/login-error', function(req, res) {
res.redirect(301, '/login');
});
router.all('/register-error', function(req, res) {
res.redirect(301, '/register');
});
// GET /homepage
router.get('/', function(req, res, next) {
req.flash('info', 'Velkommen!');
return res.render('index.pug', {
title: 'Welcome!',
url: req.originalUrl
});
});
....
// POST /login
router.post('/login', function(req, res, next) {
var body = _.pick(req.body, 'name', 'password');
if (req.body.name && req.body.password) {
db.user.authenticate(body).then(function(user) {
req.session.userId = user.id;
// To make sure the session is stored in db befor redirect
req.session.save(function() {
return res.redirect('makeitem');
});
}).catch(function(e) {
var err = new Error("Wrong username or password.");
err.status = 400;
err.message = "Wrong username or password.";
req.session.sessionFlash = {
type: 'error',
message: err.message
};
res.redirect('/login-error');
});
} else {
var err = new Error('All fields required.');
err.status = 400;
err.message = 'All fields required.';
req.session.sessionFlash = {
type: 'error',
message: err.message
};
res.redirect('/login-error');
}
});
...
// POST /register
router.post('/register', function(req, res, next) {
var body = _.pick(req.body, 'name', 'email', 'password');
// Check if all fields are filled out
if (req.body.name &&
req.body.email &&
req.body.password) {
// // Check that passwords are the same
if (req.body.password !== req.body.comf_password) {
var err = new Error('Passwords do not match.');
err.status = 400;
err.message = 'Passwords do not match.';
req.session.sessionFlash = {
type: 'error',
message: err.message
};
res.redirect('/register-error');
} else {
db.user.create(body).then(function(user) {
//res.json(user.toPublicJSON());
res.redirect('/login');
}, function(e) {
var err = new Error('Email or Shopping List Name in use.');
err.status = 400;
err.message = 'There is already a Shopping List with this name or email';
req.session.sessionFlash = {
type: 'error-name',
message: err.message
};
res.redirect('/register-error');
});
}
} else {
var err = new Error('All fields required.');
err.status = 400;
err.message = 'All fields required.';
req.session.sessionFlash = {
type: 'error',
message: err.message
};
res.redirect('/register-error');
}
});
...
I'm using pug, so this is the way I display messages:
if sessionFlash && sessionFlash.message
.sessionflash
p.bg-warning #{ sessionFlash.message }
These are my dependencies:
"dependencies": {
"bcrypt": "^0.8.7",
"body-parser": "^1.15.2",
"connect-session-sequelize": "^3.1.0",
"cookie-parser": "^1.4.3",
"crypto-js": "^3.1.6",
"express": "^4.14.0",
"express-flash": "0.0.2",
"express-session": "^1.14.1",
"jsonwebtoken": "^7.1.9",
"pg": "^4.5.6",
"pg-hstore": "^2.3.2",
"pug": "^2.0.0-beta6",
"sequelize": "^3.5.1",
"sqlite3": "^3.1.4",
"underscore": "^1.8.3"
Why is this happening? And how do I display flash messages on Heroku?