[solved] Custom field for users collection

Hi, I’m trying to add roles to the users of my project. I thought that would be best if I had a role-field in the user-collection. But I can’t figure out how to access it properly.

I have my account-config.js file inside startup/both/account-config.js
This is where I planned to add the roles since all the other account-related is there:

import { Accounts } from 'meteor/accounts-base';

Accounts.ui.config({
  passwordSignupFields: 'USERNAME_ONLY',
});

Accounts.onCreateUser((options, user) => {
  Meteor.users.update(this.userId, {$set: {role: "Member"}});
});

However, console.log says onCreateUser isn’t a function:

account-config.js:8 Uncaught TypeError: Accounts.onCreateUser is not a function
    at account-config.js (account-config.js:8)
    at fileEvaluate (modules-runtime.js?hash=d3c3e5d67c95f97a60888bda7373292efad3be5e:346)
    at Module.require (modules-runtime.js?hash=d3c3e5d67c95f97a60888bda7373292efad3be5e:248)
    at Module.moduleLink [as link] (modules.js?hash=d4228fef4dda485f45a01680ca9e75cd3c286374:354)
    at main.js (main.js:1)
    at fileEvaluate (modules-runtime.js?hash=d3c3e5d67c95f97a60888bda7373292efad3be5e:346)
    at Module.require (modules-runtime.js?hash=d3c3e5d67c95f97a60888bda7373292efad3be5e:248)
    at require (modules-runtime.js?hash=d3c3e5d67c95f97a60888bda7373292efad3be5e:268)
    at app.js?hash=f47b7979db024c43676e1a96c3ecb7dcdb4e9e4c:13947

Did I forget to import something in order to make onCreateUser work? Or is it the wrong directory I write this code in? I would appreciate any help!

onCreateUser is a server only method, so you want to put that code in startup/server/account

Thank you for the reply, the error is gone now. But it seems the role-field is not set when a new user is created. I’m using Meteor Toys to check the collections and the field role didn’t show up, even if I queried the user-collection. No error shows up though.

I read this on the documentation:

// Support for playing D&D: Roll 3d6 for dexterity.
Accounts.onCreateUser((options, user) => {
  const customizedUser = Object.assign({
    dexterity: _.random(1, 6) + _.random(1, 6) + _.random(1, 6),
  }, user);

  // We still want the default hook's 'profile' behavior.
  if (options.profile) {
    customizedUser.profile = options.profile;
  }

  return customizedUser;
});

And then I tried this

Accounts.onCreateUser((options, user) => {

  const customizedUser = String.assign({
    role: "Member",
  }, user);

  if (options.profile) {
    customizedUser.profile = options.profile;
  }

  return customizedUser;

});

in order to assign a string, not an object but that doesn’t do it either.

String.assign is not a function. You do want to use Object.assign because the user parameter is an object and you want to assign the role property to that object.

Using Object.assign is roughly the same thing as doing this:

user.role = "Member"

It’s just convenient to use when you want to copy properties from one or more objects into another. You can imagine how useful it is when you have a bunch of properties, or when you want to make a complete (shallow) copy by copying into a new and empty object (ie. Object.assign({}, user) )

So this

Accounts.onCreateUser((options, user) => {

  const customizedUser = Object.assign({
    Role: "Member",
  }, user);

  return customizedUser;
});

would work just like

Accounts.onCreateUser((options, user) => {
  const customizedUser = user.role = "Member"
  return customizedUser;
});

?

I tried both those ways and there’s still no role-field after signing in when I check with Meteor Toys.

No, this is different, you’re assigning twice in the same line, which works right to left. So:

const customizedUser = user.role = "Member"

becomes:

user.role = "Member"
const customizedUser = user.role; // aka just the string "Member" instead of the whole user
return customizedUser;

Which just returns the string "Member"

Just modify the user and return it to Meteor:

Accounts.onCreateUser((options, user) => {
  user.role = "Member"
  return user;
});

Oh, right, sorry. However, it’s still not adding the field when I do it like that.

I just have to import

import { Accounts } from 'meteor/accounts-base';

right?

Yep that’s right.
I just made a new project with the same code and it works fine

Is the role appearing on the server?
Try using meteor shell on the terminal and Meteor.users.find().fetch() to see if the new users have the role set.

The default users publication only publishes specific fields for security reasons (even with autopublish), so if you’re checking on the client and haven’t published the new data, it will only be visible on the server.

Also, have you considered using an existing roles package like alanning:roles?

1 Like

This is what I got:

[ { _id: 'uMZvSKXoyPDK5ZjGa',
    createdAt: 2019-06-26T03:54:19.304Z,
    services: { password: [Object], resume: [Object] },
    username: 'Kuroki' },
  { _id: 'omJ7e676Kf9pYCkmm',
    createdAt: 2019-08-07T00:20:12.618Z,
    services: { password: [Object], resume: [Object] },
    username: 'nah' },
  { _id: 'edyHtHx9RpWgN6Spx',
    createdAt: 2019-08-07T00:34:46.477Z,
    services: { password: [Object], resume: [Object] },
    username: 'test' },
  { _id: 'wc3BakQCMCCBTfn6y',
    createdAt: 2019-08-07T00:54:37.416Z,
    services: { password: [Object], resume: [Object] },
    username: 'test5' } ]

All accounts, except Kuroki were created after I inserted the onCreateUser function. Is it possible that the whole user-collection has to be empty in order to work? Because the new field is somehow interfering with old documents which don’t have the the new field?

I have considered the roles-package - I actually installed it but since all I need, I think, is just a role-field with a string to determine which users can access special content like a adminpanel and such. But I might go there if I can’t figure out onCreateUser.

Thats weird. I changed the file to the api-folder and it worked. But both directories (startup and api) are imported by the server.

1 Like

Very strange! Glad you got it working :smile: