2
  postRegistrationHandler: function (account, req, res, next) {
    console.log('postRegistrationHandler activated');
    account.getCustomData(function(err, data) {
      if (err) {
        console.log(err.toString, "error string");
        return next(err);
      } else {
        data.mongo_id = userCreationCtrl(account);
        data.save();
        next();
      }
    });
  },

This function almost works properly, but the line:

        data.save();

runs before the previous line finishes which means that the data I want to save isn't present at the appropriate time.

        data.mongo_id = userCreationCtrl(account);

This line calls a function that creates a mongoDB document with information in the account object and then returns the _id (which is what I am trying to save.

I thought maybe using a .then() would help but that seems to be unavailable here for some reason. If anyone sees something I'm missing, that would be quite helpful. Thank you!

Here is the userCreationCtrl file as requested:

var UserSchema = require('./../models/UserModel.js');

var createNewUser = function (account, res, next){
  // We will return mongoId after it is created by submitting a newUser
  var mongoId = "";
  // Save StormpathID (last 22 characters of account.href property)
  var newStormpathId = account.href.slice(account.href.length - 22);
  console.log('stormpath ID:', newStormpathId, 'just registered!');
  console.log(account);
  // Create new user from model by recycling info from the Stormpath registration form and include the stormpathId as well.
  var newUser = new UserSchema({
      stormpathId: newStormpathId,
      firstName: account.givenName,
      lastName: account.surname,
      email: account.email,
      street: account.street,
      city: account.city,
      zip: account.zip
  });
  // This saves the user we just created in MongoDB
  newUser.save(function(err, result){
      console.log(result);
      if (err) {
            console.error(err);
      }
      else {
        console.log("User created in MongoDB, attempting to return mongoDB _id to stormpath customData");
        // Keep track of the new user's mongo _id so we can return it to the previous function and save it as Stormpath custom data.
        mongoId = result._id;
        console.log(mongoId, "mongoid");
        return result._id;
      }
  });
};

module.exports = createNewUser;
Brian Bauer
  • 135
  • 10
  • 1
    Can you post the contents of the `userCreationCtrl` function? – Nate Barbettini Jun 27 '16 at 22:13
  • Yes, I've edited it into the original question. – Brian Bauer Jun 27 '16 at 22:54
  • 1
    `userCreationCtrl` takes 3 arguments and you are passing only 1. Instead of returning from it `result._id` just call callback with that result and also inside that callback call `data.save()` – Krzysztof Safjanowski Jun 27 '16 at 22:58
  • `createNewUser()` is asynchronous (because `newUser.save()` is asynchronous). The results can only be returned form that via a promise or a callback, but you are trying to return the result synchronously and that does not work. This is a classic "How do I return a value from an async operation" issue as described here [How do I return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call). – jfriend00 Jun 27 '16 at 23:00

1 Answers1

2

You have userCreationCtrl expecting 3 arguments, account, res, and next. next is the callback that should be called after the user is created so instead of return result._id you should call next like so:

// inside of createNewUser()
newUser.save(function(err, result){
  console.log(result);
  if (err) {
    console.error(err);
  }
  else {
    console.log("User created in MongoDB, attempting to return mongoDB _id to stormpath customData");
    // Keep track of the new user's mongo _id so we can return it to the previous function and save it as Stormpath custom data.
    mongoId = result._id;
    console.log(mongoId, "mongoid");

    // IMPORTANT change to make it all work...
    // get rid of return result._id because its not doing anything
    // pass the value to your callback function instead of returning the value
    next(null, result._id);
  }
});

then calling code in postRegistrationHandler should look like this:

account.getCustomData(function(err, data) {
  if (err) {
    console.log(err.toString, "error string");
    return next(err);
  } else {
    // pass in a callback as the 3rd parameter that will be called by newUser.save() when its finished
    userCreationCtrl(account, null, function(err, resultId) {
      data.save();
      next();
    });
  }
});
Ryan
  • 5,845
  • 32
  • 27
  • 1
    That's all fine and dandy, but if `userCreateCtrl()` is actually `createNewUser()` in the code the OP posted, then `createNewUser()` is not using a callback to communicate when it's done so this is only one piece of what needs to be done. – jfriend00 Jun 27 '16 at 23:03
  • that's what my first line of code is referring to... replace `return result._id;` with `next(null, result._id);` – Ryan Jun 27 '16 at 23:07
  • userCreateCrtl() is indeed createNewUser() I probably could have named them the same thing for clarity... – Brian Bauer Jun 27 '16 at 23:08
  • @Ryan - That's not very clear to me (still not quite sure what you're suggesting). You could include more code around your suggested change in context to make it clearer. – jfriend00 Jun 27 '16 at 23:43
  • @jfriend00 I think we are saying the same thing - I added more code so hopefully it helps to clarify. I didn't want to repost all the code because then its hard to see the two minor changes that need to be made. If the OP wants me to repost all of it, I will. – Ryan Jun 28 '16 at 00:29
  • Thanks very much for the assistance. I've got working code now and this helped me learn a lot. I really appreciate it. – Brian Bauer Jun 28 '16 at 03:11