I'm trying to use the 'roles' package available on Atmosphere but I can't get it to work with Accounts.onCreateUser(), I can get the example on github. When I register a user, I want to add a role to them, when I test whether the role is assigned, it's not picking it up.
Here's my code
/server/users.js
Accounts.onCreateUser(function(options, user){
var role = ['admin'];
Roles.addUsersToRoles(user, role);
return user;
});
/client/page.js
Template.hello.events({
'click input': function () {
var loggedInUser = Meteor.user();
if (Roles.userIsInRole(loggedInUser, ['admin'])) {
console.log("Hi Admin!");
}else{
console.log("Please Log In");
}
}
});
If you look at the code being used in the Roles
package you will see that they use your passed in user/userId to perform a query on the user's collection (here, starting at line ~623):
try {
if (Meteor.isClient) {
// On client, iterate over each user to fulfill Meteor's
// 'one update per ID' policy
_.each(users, function (user) {
Meteor.users.update({_id: user}, update)
})
} else {
// On the server we can use MongoDB's $in operator for
// better performance
Meteor.users.update(
{_id: {$in: users}},
update,
{multi: true})
}
}
Since onCreateUser
is called before the user object is inserted into the collection (docs: The returned document is inserted directly into the Meteor.users collection), Roles
cannot find it when it performs the query.
In order to fix this you must wait until the user is inserted into the collection. If you look at the Roles
package all of their examples show this. Like here, (second example, comments added), along with many others:
// insert user and retrieve the id
id = Accounts.createUser({
email: user.email,
password: "apple1",
profile: { name: user.name }
});
// now we can verify that the user was inserted and add permissions
if (user.roles.length > 0) {
Roles.addUsersToRoles(id, user.roles);
}
Hope that shines some light on your issue. So basically just insert the user and then add the permissions after.
To add things to a user document after it has been inserted by the accounts
package, try this pattern. Note, you must meteor add random
in order to generate a userId
, which is safe to do in this context.
Accounts.onCreateUser(function (options, user) {
// Semantics for adding things to users after the user document has been inserted
var userId = user._id = Random.id();
var handle = Meteor.users.find({_id: userId}, {fields: {_id: 1}}).observe({
added: function () {
Roles.addUsersToRoles(userId, ['admin']);
handle.stop();
handle = null;
}
});
// In case the document is never inserted
Meteor.setTimeout(function() {
if (handle) {
handle.stop();
}
}, 30000);
return user;
});
The accepted answer forces you to write boilerplate code for login logic given by meteor through accounts-ui/password. The other answers make assumptions about the underlying implementation and the timeout solution introduces a race condition.
Why not do this:
Accounts.onCreateUser(function(options, user) {
...
Meteor.setTimeout(function () {
Roles.addUsersToRoles(user._id, roles, group);
},0);
...
});
You effectively add the role after whatever it is that triggered the onCreateUser call and use alanning's api to add to roles. (Tested with meteor 1.0, roles 1.2.13)
I don't understand how to integrate Roles.addUsersToRoles with the onCreateUser function called when a user is created. It doesn't work when it's called within OnCreateUser as you've done, as you've found. But the example case of calling addUsersToRoles within a user creation loop doesn't seem applicable to the normal use case of a new user creating an account.
Instead, I just do:
Accounts.onCreateUser(function(options, user){
var role = ['admin'];
user.roles = role
return user;
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With