Let\'s say I have a todo app, and I want to make sure that every user that registers has at least one todo to start with, something like \"First todo to cross off!\", how wo
The Meteor API now has the hook onCreateUser:
Accounts.onCreateUser(function (options, user) {
Todos.insert({
owner: user._id,
text: "First todo to cross off!",
});
// We still want the default hook's 'profile' behavior.
if (options.profile)
user.profile = options.profile;
return user;
});
I used the _.wrap method described above but wanted to include an additional suggestion. It's a good idea to call the original callback from your new custom callback. Meteor does some things on the callback that we don't want to miss.
Modified code that worked like a champ for me:
Accounts.createUser = _.wrap(Accounts.createUser, function(createUser) {
// Store the original arguments
var args = _.toArray(arguments).slice(1),
user = args[0];
origCallback = args[1];
var newCallback = function(error) {
// do my stuff
origCallback.call(this, error);
};
createUser(user, newCallback);
});
I think this answer this question better: How can I create users server side in Meteor?
in resume:
Accounts.createUser({
username: username,
email : email,
password : password,
profile : {
//publicly visible fields like firstname goes here
}
});
check the meteor docs for more: http://docs.meteor.com/#/full/accounts_createuser
postSignUpHook
now exists.Splendido just merged my pull request for exactly this issue.
AccountsTemplates.configure({
/*...*/
postSignUpHook: /*[callback with your actions post full user creation goes here]*/,
/*...*/
}
Documentation (You'll need to scroll down it's the last hook):
func(userId, info) Called, server side only, just after a successfull user account creation, post submitting the pwdForm for sign-up: allows for custom actions on the data being submitted after we are sure a new user was successfully created. A common use might be applying roles to the user, as this is only possible after fully completing user creation in alanning:roles. The userId is available as the first parameter, so that user object may be retrieved. The password is not available as it's already encrypted, though the encrypted password may be found in info if of use.
One of the Meteor devs answered this question in Meteor google group: https://groups.google.com/forum/?fromgroups=#!topic/meteor-talk/KSz7O-tt4w8
Basically, right now, there is no createUser hook when using accounts-ui, only when programmatically doing so via Accounts.createUser
. Also, there are no hooks for login, unless using the lower-level login functions like loginWithFacebook
, etc. I haven't figured out an ideal way around this yet, but a few ways of handling it:
if needing to enter a default value into a collection, in that collection's subscription, use the onComplete argument. In this callback, if there are no entries in collection, add one. This avoids the first problem I mentioned in my post about not knowing when a collection was loaded, though not ideal since collection could be empty because user already removed first default one:
Meteor.subscribe 'todos', user: Meteor.userId(), () ->
todo = Todos.findOne()
unless todo
Todos.insert user: Meteor.userId()
you can set up a login hook by using the Meteor.autorun
reactive method to check for a change in Meteor.userId(). That'll only get called when the user logs in/reloads the page. This is more useful for non-collection stuff since the collection is not guaranteed to be loaded when Meteor.userId is set:
Meteor.autorun () ->
if Meteor.userId()
console.log 'Do some post login hook'
So I think the efficient solution is still out there somewhere, but wanted to update this post with workarounds I had found in the meantime.
You can piggyback onto functions that are called by Meteor by wrapping them. I'm also using the accounts-ui and accounts-password packages and I use Underscore's _.wrap method to redefine the loginWithPassword function. Underscore is included in Meteor by default.
I use something like this for logging in:
Meteor.loginWithPassword = _.wrap(Meteor.loginWithPassword, function(login) {
// Store the original arguments
var args = _.toArray(arguments).slice(1),
user = args[0],
pass = args[1],
origCallback = args[2];
// Create a new callback function
// Could also be defined elsewhere outside of this wrapped function
var newCallback = function() { console.info('logged in'); }
// Now call the original login function with
// the original user, pass plus the new callback
login(user, pass, newCallback);
});
In this specific case, the code above would go in your client code somewhere.
For Accounts.createUser, it might look something like this (also somewhere in client code):
Accounts.createUser = _.wrap(Accounts.createUser, function(createUser) {
// Store the original arguments
var args = _.toArray(arguments).slice(1),
user = args[0],
origCallback = args[1];
// Create a new callback function
// Could also be defined elsewhere outside of this wrapped function
// This is called on the client
var newCallback = function(err) {
if (err) {
console.error(err);
} else {
console.info('success');
}
};
// Now call the original create user function with
// the original user object plus the new callback
createUser(user, newCallback);
});
Hope that's helpful.