Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unable to add roles to user with meteor using 'roles' package

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");
    }
  }
});
like image 565
user1627990 Avatar asked Mar 26 '14 01:03

user1627990


4 Answers

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.

like image 71
Firo Avatar answered Sep 20 '22 10:09

Firo


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;
});
like image 29
DoctorPangloss Avatar answered Sep 17 '22 10:09

DoctorPangloss


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)

like image 21
Joe Avatar answered Sep 19 '22 10:09

Joe


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;
});
like image 44
dojomouse Avatar answered Sep 18 '22 10:09

dojomouse