Search code examples
meteorrolesiron-router

Do Meteor-Roles and Iron-Router play nicely together?


I have a Meteor app with an editor page that should only be accessible to editors. I am using Iron-Router and my Router.map looks like the following. However, this is not working in an odd way. If I provide a link to the editor page, then all is well, but if I try entering the /editor url, then it always redirects to home, even if the user role is correctly set.

(One thing I ruled out was if Meteor.userId() is not set before Roles.userIsInRole is called in before.)

Anyone know why this would be?

Router.map(function() {
      ...
      this.route('editor', {
        path: '/editor',
        waitOn: function() {
          //handle subscriptions
        },
        data: function() {
          //handle data
        },
        before: function() {
          if ( !Roles.userIsInRole(Meteor.userId(), 'editor') ) {
            this.redirect('home');
          }
        }
      });
      ...
});

Solution

  • The Roles package sets up an automatic publication that sends the roles property on the Meteor.users collection. Unfortunately, you can't get a subscription handle for automatic publications, so you'll need to make your own.

    Set up a new subscription that publishes the required data of a user, then configure Router to check that the data is ready before showing any page.

    eg:

    if (Meteor.isServer) {
      Meteor.publish("user", function() {
        return Meteor.users.find({
          _id: this.userId
        }, {
          fields: {
            roles: true
          }
        });
      });
    }
    
    if (Meteor.isClient) {
      var userData = Meteor.subscribe("user");
      Router.before(function() {
        if (Meteor.userId() == null) {
          this.redirect('login');
          return;
        }
        if (!userData.ready()) {
          this.render('logingInLoading');
          this.stop();
          return;
        }
        this.next(); // Needed for iron:router v1+
      }, {
        // be sure to exclude the pages where you don't want this check!
        except: ['register', 'login', 'reset-password']
      });
    }