Alanning:roles v3 released

Changes between 2.x and 3.0

Breaking changes

  • The roles a user has assigned are no longer stored in the collection users but have been moved to a separate collection called role-assignment , available at Meteor.roleAssignment. You might need to update your schema and places you access the collections directly.

  • The roles a user has are not published automatically anymore. If you want all the roles a user has to be published automatically you can use the following code:

    Meteor.publish(null, function () {
      if (this.userId) {
        return Meteor.roleAssignment.find({ 'user._id': this.userId });
      } else {
        this.ready()
      }
    })
    
  • The behavior of getRolesForUser() used with the option fullObjects has changed. If you need the old behavior, use the code of this change-set: Meteor-Community-Packages/meteor-roles/#41d2ed493852f21cf508b5b0b76e4f8a09ae8f5c

New options

  • removeUsersFromRoles() got the option anyScope to remove all the roles a user has.
  • getRolesForUser() got the new option onlyScoped to limiting the result to only scoped permissions

Details and reasoning can be found in #270 and #276

Migration to 3.0

If you are currently using this package in a version older than 2.x, please upgrade to 2.0 first by running the migration script: https://github.com/Meteor-Community-Packages/meteor-roles/tree/v2#migration-to-20

In meteor-roles 3.0, roles are stored differently in the database. To migrate the database to the new schema, run Meteor._forwardMigrate2() on the server. Please take a backup of the users collection before migrating.

meteor shell
> Package['alanning:roles'].Roles._forwardMigrate2()

In case something fails, there is also a script available for rolling back the changes. But be warned that a backward migration takes a magnitude longer than a forward migration. To migrate the database back to the old schema, run Meteor._backwardMigrate2() on the server:

meteor shell 
> Package['alanning:roles'].Roles._backwardMigrate2()

Future of 1.x and 2.x

If you want to keep using this package in version 1.x or 2.x, I’ll support them as good as I can and help you fixing bugs and keep them compatible with upcoming Meteor versions as I can, but all future development will be focussed on the latest major version.

Going forward

At first I want to give the credits and a big thanks to @alanning and @mitar for developing the package so far. Both mentioned in #270 that their time on developing this package got very limited, which is the reason why I picked it up after moving it into the Meteor Community Packages group.

I already have some plans for the next major version in mind which will focus on tree-shaking. In all our versions, roles have been stored in a collection accessible at Meteor.roles, but this collection could equally well be imported when you want it.

I would really appreciate if this package could be an example of collaboration and team effort. Every kind of help is appreciated and very welcome!

Thanks also to @storyteller for proofreading this :blush:

15 Likes

Good to read this is still actively developed and congrats for releasing a new version! :clap:

However…

The roles a user has are not published automatically anymore.

I wonder what the design decision is for this? Is there a scenario were you would use roles and don’t want to know them in the client?

2 Likes

What was the reason for moving roles to a separate collection? I imagine that will cause a performance hit as it will require more reads, which may be minor but could increase costs at a large scale

1 Like

Also, moving it out of the users collection would prevent it being available in the MergeBox cache via msavin/userCache, which in my case eliminated a LOT of db lookups just to check a user’s roles.

Maybe Alanning:roles could check the MergeBox cache itself, since I imagine that in most cases developers will choose to autopublish a user’s roles.

3 Likes

In my case, we grant permissions on a per-document basis (think of a file-system where you grant access to files and folders). Storing all this in the user and shipping it to the client every time a user opens the application, was getting worse over time in our example. By this change here, I think I introduced a system which easily can scale in amount of users and assignment of roles.

You can find more details in the ticket #270 in the project repository.

1 Like

As of what I saw, the database calls didn’t increase and the objects received are often smaller than in v2. I added some considerations to the original pull request #276. If you see it getting worse or see some code which you think is in risk of decreasing the performance, I’d like to hear from you.

Well - technically they will be in the MergeBox, but they won’t be part of the users document which is why the extension wouldn’t take it.

But I would be grateful if if you could create a ticket in the repository for this feature. The better if you also have a way in mind of how this could be implemented - a PR would be awesome!

By necessity doesn’t it have to increase the calls? In v2 you would only query the users collection for a single user. In v3 you will query the users collection and the roles collection for a single user, unless I’m not understanding this correctly.

I will create a ticket for the MergeBox feature, however, I’ve just discovered a problem with the msavin:userCache approach (it’s not reactive so can only safely be used in Methods, not Publications). I’ve raised a bug on userCache here. Until we’ve (@msavin) found a work-around for that then I would steer clear of MergeBox…

Hi,

For routing purposes it is useful to know a users role, in order to prevent a user navigating to restricted pages.

I see that the new v3 behaviour does not automatically publish a user’s roles to the client.

The readme recommends publishing the user’s roles to the client like so

Meteor.publish(null, function () {
  if (this.userId) {
    return Meteor.roleAssignment.find({ 'user._id': this.userId });
  } else {
    this.ready()
  }
})

How do you rate-limit this ‘null’-named publication to protect it from abuse?

I rate-limit my publications like so:

    DDPRateLimiter.addRule(
      {
        name,
        'subscription',
        connectionId: () => true
      },
      5,
      10000
    );

Thanks

1 Like

Well, in v2 you could give the full-fledged user-document to the function. In this case, most of the functions didn’t access the database at all - only if you gave it the users id as a string it would query the users database, for the document of the current user.

In v3, the system always queries a database called role-assignments. For backwards compatibility you can provide each function with the users document or his id. In any case, the system will query the database on the collection role-assignments, which only returns the data required - not all the other roles the user is assigned to.

If you want more, I want to encourage you to take a look at the source-code. It’s not very complicated :wink:

1 Like

Well, this is just a sample which I picked from the documentation of Meteor: https://docs.meteor.com/api/pubsub.html

You can, of course, take more control over this publication, which is why I added it as a sample. This is one way of doing it if you want to stay close to how v2 did it. In my application I have a more controlled way of publishing the role-assignments.

1 Like

Not a huge fan of the decision to move the roles out of the user document. I try to avoid unnecessary
publications as much as possible, as every publication means another load impact on the server.

3 Likes

I wonder if you could use a method call, with some periodic refreshes? Auto-publishing the roles set is one way to simulate how it used to work, but you might also be able to hit the database just once over a method (keeping in mind the data can go stale), and then use that somehow. I haven’t looked very closely at how we might do that, because I think the publication overhead for this in my app will be quite small. The convenience of an autopublished roles is worth the trade off for me, at least until I need more extreme scalability. Actually, it shouldn’t even be all that much more overhead than having it as part of the user document, which is also pub/sub if I understand correctly - seems more of a lateral move.

2 Likes

I’d like to elaborate a bit on this, because the separation of collections (in my eyes) does not increase the load on the server, since it’s the same amount of data processed - just now in two separate collections. In my case it even decreases.

I’m using the package redis-oplog where I can only listen to changes on a certain user on a certain scope. This way, the server doesn’t have to check for changes on roles in a different scope - as far as I know.

Another side-benefit is, that if you change a role, the value returned by Meteor.user() on the client triggers a rerun on a reactive context in v2, but not in v3.

1 Like