I am really struggling with what is probably a very simple concept. When a new user is created, I want to initialize a user’s account with a bunch of rows (documents) in some database collections.
I can’t for the life of me figure out where that code should go. I have tried placing it in a helper which is called by the template that would use those records, by doing:
But because of the reactivity it always returns a 0 on the first pass and so I always insert new records. In other words, I believe the way I am doing it is not idempotent.
I don’t think putting it in a helper is the right place, but I have no clue where else to put it. I’m betting there is some magic reactive event fired when someone first creates a new account and logs in for the first time?
If I want to create a bunch of records one time, when a user first creates their account using the accounts-password function, where should I place that code?
Bah, this doesn’t help me at all. I can only manipulate the user object before it’s added to the database. How do I add collection records after the user is added to the database?
And if anybody wants to explain to my pea-brain why find().count() returns 0 the first time it’s called and then is called again and returns the correct number of rows, that would be super cool. I am sure it has something to do with reactivity, but I can’t wrap my brain around it.
@riebeekn are you sure about this? The user object does not have an _id within the onCreateUser block and it gets one only after the user is actually successfully created.
So your code should actually be:
Accounts.onCreateUser(function(options, user) {
if(!options || !user) {
console.log('error creating user');
return;
}
// make sure the user actually gets an ID
// _makeNewID() is an undocumented feature and may change in the future
user._id = Meteor.users._makeNewID();
// add default exercises
Meteor.settings.defaultExercises.forEach(function(exercise) {
Exercises.insert({
name: exercise.name,
description: exercise.description,
userId: user._id
});
});
// add more stuff to other collections
// ...
return user;
});
@alfreema there are two other possible ways that I’ve used before to initialize user related persisted data upon user creation. One is from @awatson1978’s meteor-cookbook
Meteor.users.find({ initialized: { $exists: false } }, { fields: { _id: 1 } }).observe({
added: function (user) {
// insert default user docs here if not already present
Meteor.users.update(user._id, { $set: {initialized: true} });
}
});
Meteor.users.after.insert(function (userId, doc) {
// the currently logged in user if there is any (might be different than the new user
console.log(userId);
// the new user's id
console.log(this._id);
// the same
console.log(doc._id);
// the user document itself
console.log(doc);
});
I see the id value and looking at my documents in Robomongo everything seems good. I haven’t messed with this code for awhile but I don’t recall / see anything funky I’m doing to get the id within the onCreateUser block.
Seems to me that both techniques have their place. riebeekn’s technique would be good for log tables, while serkandurusoy’s techniques are better where orphaned records are undesirable (the general situation).
I like the cleanliness/maintainability of the collection-hooks example. I think I’ll go that route for now.
Yep, there is some confusion there. And I think having an _id there does not help either. It further strengthens the misconception that onCreateUser is a post hook, which (un)clearly is not.
I believe a better fix would be not making _id available at all