Trying to update res.locals after database update - node.js

When updating a user (via database update) in my Node.JS Express app, I update a user session which then updates a res.locals.session
However, when I try to access the res.locals.session within the Jade template, the values are displayed as they were prior to the database update.
Please can you help me to find out why the res.locals.session is not updating in the template?
Here is my code (cut down for brevity):
index.js
// Store session to locals so I can use it in Jade
app.use(function (req, res, next) {
res.locals.session = req.session;
next();
});
routes/user.js
var User = require('../models/Users');
function displaySettings(req, res) {
res.render('settings');
}
function saveSettings(User, req, res) {
// Updating user
User.update(
{ Member_id: req.session.user.Member_id }
, { settings: req.body }
, { upsert: false, multi: false }
, function (err) {
//if(err) return next(err);
//res.json({ message : 'Success!'});
console.log("saved");
});
// Retrieving user again, so that I can resave the updated user's details
// in the res.locals.session
var user = User.findById(req.session.user._id, function (err, user) {
console.log("found");
console.log(user);
req.session.user = user;
console.log(req.session.user);
res.locals.session = req.session;
console.log(res.locals.session);
});
// Finally display the view
displaySettings(req, res);
}
views/settings.jade
extends layout
block content
include includes/navigation
div.container.main
h1.text-center User Settings
div.row
div.col-md-6.col-md-offset-3
form#form-login.form-horizontal(action='/settings',method='post')
div#container(data-role='fieldcontain')
fieldset(data-role='controlgroup')
div.form-group
label.col-sm-4.control-label(for='username') Paypal Email
div.col-sm-8
// The session.user.settings.paypalEmail is showing
// the old value even after the user has re-saved
// their settings. I'm expecting the new, updated
// value to be displayed instead
input.form-control(id='username',type='text',value='#{session.user.settings.paypalEmail}',name='paypalEmail')

Try using res.redirect('settings') instead of calling displaySettings(req, res). I think this will allow res.locals to update.

what about rewriting the saveSettings as follows.
function saveSettings(User, req, res) {
// Updating user
User.update(
{ Member_id: req.session.user.Member_id }
, { settings: req.body }
, { upsert: false, multi: false }
, function (err) {
//if(err) return next(err);
//res.json({ message : 'Success!'});
console.log("saved");
// Retrieving user again, so that I can resave the updated user's details
// in the res.locals.session
var user = User.findById(req.session.user._id, function (err, user) {
console.log("found");
console.log(user);
req.session.user = user;
console.log(req.session.user);
res.locals.session = req.session;
console.log(res.locals.session);
// Finally display the view
displaySettings(req, res);
});
});
}

Related

db.collection.find not working

On my project with node and mongodb db.collection.find just not working. In routes.js file there is a function getUser() that tried to find a user by user_id, but finds nothing. I tried to do the same with same parameters on console and everything works fine.
How to invoke the error: go to your profile page, create an item and redirect back to the profile page, then refresh it. Because of that a profile.ejs file can't be executed.
function getUser(user_id) {
var items;
User.find({'user.id': user_id}, function(err, users) {
if(err) throw err;
items = users;
return items;
});
}
app.get('/profile', isLoggedIn, function (req, res) {
wasMessageShown(app.locals.answerObj);
console.log(req.user);
var user;
if(req.user.user.id){
user = req.user;
} else {
user = getUser(req.user.item.user_id);
}
res.render('profile.ejs', {
user: user,
messageSuccess: app.locals.answerObj.messageSuccess,
messageFailure: app.locals.answerObj.messageFailure
});
});

Node.js / Express.js Removing user from request, removes it from database

Here is the code:
exports.delete = function (req, res, next) {
console.log(req.user);
req.user.remove(function (err) {
if(err) {
return next(err);
} else {
res.json(req.user);
}
})
};
Of course this function is callback of delete method, what I don't understand is that, why removing req.user also deletes the specific user from MongoDB, as it is just a request.
Edit:
I have another callback(GET) which is executed on the same route:
exports.userByID = function (req, res, next, id) {
User.findOne({
_id: id
}, function (err, user) {
if (err) {
return next(err);
} else {
req.user = user;
next();
}
});
};
User is MongoDB model.
Where you do your req.user = user you're setting the value of req.user to the instance of your mongodb model.
So, calling req.user.remove is in fact calling your mongodb model remove function.
Change your delete function to:
exports.delete = function (req, res, next) {
console.log(req.user);
delete req.user
//etc...
};
delete req.user will remove the user object from your request object

NodeJs - calling one method from another in server controller

With the following controller, how can I call one method from another in the same controller?
Specifically, calling login() within a successful signup(), while retaining the same functionality for login() when it is used by a form?
The line this.login(newUser) does not work, nor does plain old login(newUser)
In both scenarios, I get the error:
TypeError: Cannot call method 'login' of undefined
var mongoskin = require('mongoskin');
module.exports = {
login: (function (req, res) {
req.db.collection('auth').findOne({_id: mongoskin.helper.toObjectID(req.body.id)},
function (err, results) {
// log person in and send results to client
}
)
}),
signup: (function (req, res) {
var user = req.body;
req.db.collection('auth').insert(user, function (err, newUser) {
// after adding user, automatically log them in
// does not work:
//login(newUser, function (err) {
// do something
//})
// does not work:
this.login(newUser, function (err) {
// do something
})
}
)
})
}
Controllers should be doing as little as possible, and should orchestrate the work required by executing functions stored elsewhere.
View this gist - click here
What I have done is created "services" that are not tied to the client request, therefore re-usable everywhere.
Hope this helps.
Thanks to Dave Newton
var mongoskin = require('mongoskin');
var myCollection = 'auth';
Solution
function localLogin(db, myCollection, user, res){
db.collection(myCollection).findOne({_id: mongoskin.helper.toObjectID(user._id)},
function(err, user){
res.send({ token: createToken(user) });
});
module.exports = {
login: (function (req, res) {
var user = req.body;
localLogin(req.db, myCollection, user, res)
},
signup: (function (req, res) {
var user = req.body;
req.db.collection(myCollection).insert(user, function (err, newUser) {
// after adding user, automatically log them in
localLogin(req.db, myCollection, newUser, res)
})
}
) }) }

Express.js session undefined in method put

Building an API with node and express. In my "home" route i set a session with a users id.
When i want to add and update information on a user i want to access the session to know which user to update. In my get routes i can access the session, but in my route with put method its always undefined. Why is this?
app.get('/users/:id/spots', spot.findSpotsByUserId); //I set the session in this method
app.get('/spots/:id', spot.findById);
app.put('/userspot/spot/:spotId/add'', spot.addUserSpot);
exports.findSpotsByUserId = function(req, res) {
var id = req.params.id; //Should ofc be done with login function later
db.collection('users', function(err, collection) {
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, user) {
if (err) {
res.send({'error':'Couldnt find user'});
} else {
req.session.userId = id;//<----- sets session
console.log("SESSION",req.session.userId);
}
......}
exports.findById = function(req, res) {
var id = req.params.id;
console.log('Get spot: ' + id);
console.log("SESSION!",req.session.userId);// <----prints the id!
db.collection('spots', function(err, collection) {
collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
res.send(item);
});
});
};
exports.addUserSpot = function(req, res) {
var user = req.session.userId;
var spot = req.params.spotId;
console.log("SESSION!",req.session.userId);// always UNDEFINED!
//........}
You are looking for req.params.userId, not req.session.
The session is persisted between multiple calls, and it has no connection to the params object. You can set req.session.userId in a previous call and access it here, but I don't think this is what you want.
Try this:
exports.findById = function(req, res) {
req.session.test = "from findById";
...
};
exports.addUserSpot = function(req, res) {
console.log(req.session.test, req.params.userId);
...
};

Response will not return when trying to save model with Mongoose in Restify API

I am building an API using Restify and Mongoose for NodeJS. In the method below after finding the user and verifying their password, I am trying to save some login information before sending the response back to the user. The problem is the response will never return. If I place the response outside and after the save call, the data never gets persisted to MongoDB. Am I doing something wrong? And help would be great as I have been working on this for the past 2 days.
login: function(req, res, next) {
// Get the needed parameters
var email = req.params.email;
var password = req.params.password;
// If the params contain an email and password
if (email && password) {
// Find the user
findUserByEmail(email, function(err, user) {
if (err) {
res.send(new restify.InternalError());
return next();
}
// If we found a user
if (user) {
// Verify the password
user.verifyPassword(password, function(err, isMatch) {
if (err) {
res.send(new restify.InternalError());
return next();
}
// If it is a match
if (isMatch) {
// Update the login info for the user
user.loginCount++;
user.lastLoginAt = user.currentLoginAt;
user.currentLoginAt = moment.utc();
user.lastLoginIP = user.currentLoginIP;
user.currentLoginIP = req.connection.remoteAddress;
user.save(function (err) {
if (err) {
res.send(new restify.InternalError());
return next();
}
// NEVER RETURNS!!!!
// Send back the user
res.send(200, user);
return next();
});
}
else {
res.send(new restify.InvalidCredentialsError("Email and/or password are incorrect."));
return next();
}
});
}
else {
res.send(new restify.InvalidCredentialsError("Email and/or password are incorrect."));
return next();
}
});
}
else {
res.send(new restify.MissingParameterError());
return next();
}
},
One cause of this issue can be if you have a pre save hook which errors silently.
If you find your model as a .pre('save' () => {...}) function then double check this method is reached after you call save, and that it returns without errors.
Documentation on mongoose middleware can be found here

Resources