Meteor: Why is Iron Router's onBeforeAction called multiple times?
Asked Answered
C

1

5

When I visit a route in my browser I expect Iron Router to call onBeforeAction once before loading the route. But it looks like it is being called 3 times when first loading the route.

This is an issue for me because I want to put code that redirects the user if they do not have access to that document.

onBeforeAction: ->
  console.log 'called once' #Called 3 times when first loading the route!
  thread = Research.findOne(@params._id)
  console.log thread # This is undefined at first run
  thread = Research.findOne(@params._id)
  if thread?
    Meteor.subscribe 'collabUsers', @params._id
  else
    Router.go '/research'

Since it is called multiple times, it causes issues with redirecting. First users that do have access are also redirected because at first thread is undefined.

What I am trying to do if check if the user has access to the data the route depends on, if not then I need to redirect the user. So that is why in onBeforeAction I am trying to pull a document from database and if it exists then I will load the page or else I will redirect or throw and error message at the user.

But I notice that the console.log statement in onBeforeAction is called 3 times when the route is first loaded. And also on the first run the user does not have access to any research threads for some reason (I believe the subscription has not been setup and documents are not accessible on first run) So that causes issues with my trying to see if they have access to the document because on first run nobody has access.

Here is the entire router.coffee code

appendUserData = (array) ->
  _.each array, (item) ->
    user = Meteor.users.findOne(item.userId)
    if user?.profile.firstName? && user?.profile.lastName?
      item.firstName = user.profile.firstName
      item.lastName = user.profile.lastName
      item.username = user.username

userEnabled = () ->
  if Meteor.user()
    if $(window).width() > 768
      if !$('.show-left').hasClass 'active'
        Meteor.defer ->
          $('.show-left').click()

requireLogin = (pause) ->
  if !Meteor.user()
    @setLayout 'layoutLoggedOut'
    if Meteor.loggingIn()
      @render @loadingTemplate
    else
      @render 'login'
      pause()
  else
    @setLayout 'layout'
    if window.location.pathname is '/' or undefined
      Router.go('addAndSearchPosts')
    else
      Router.go(window.location.pathname)

Router.configure 
  layoutTemplate: 'layout'
  loadingTemplate: 'loading'
  onBeforeAction: ->
    #this code get which ids we need to get data from to render template. Here we need to get data to notification of collab
    params = {}
    params.threadIds = []
    params.userIds = []
    notifications = Notifications.find {userId: Meteor.userId()}
    notifications.forEach (notification) ->
      params.threadIds.push notification.threadId
      params.userIds.push notification.requesterId

    @subscribe('notificationDataCollab', params).wait()
  waitOn: ->
    [
      Meteor.subscribe 'myResearch', Meteor.userId()
      Meteor.subscribe "notifications"
    ]


Router.onAfterAction userEnabled
Router.onBeforeAction requireLogin,
  except: 'template1'
Router.onBeforeAction 'loading'
Router.onBeforeAction ->
  Errors.clearSeen()

Router.map ->
  @route 'posts_page',
    path: '/posts',
  @route 'template1',
    path: '/template1',
  @route 'login',
    path: '/',
  @route 'addAndSearchPosts',
    path: '/bookmarks',
    waitOn: ->
      Meteor.subscribe 'myBookmarks', Meteor.userId()
    data: ->
      bookmarks: Bookmarks.find
        _userId: Meteor.userId()
  @route 'research',
    path: '/research/:_id',
    waitOn: ->
      [
        Meteor.subscribe 'threadNotes', @params._id, Meteor.userId()
        Meteor.subscribe 'collabUsers', @params._id
      ]
    onBeforeAction: ->
      console.log 'called once'
      #Meteor.subscribe 'collabUsers', @params._id
      # thread = Research.findOne(@params._id)
      # console.log thread
      #thread = Research.findOne(@params._id)
      # if thread?
      #   Meteor.subscribe 'collabUsers', @params._id
      # else
      #   Router.go '/research'
        #Errors.throw('Thread does not exist or you do not have access', false)
    data: ->
      # this code is for appending the user data to pending and current collaborators for this thread
      thread = Research.findOne(@params._id)
      if thread?.pending?.collaborators?.length > 0
        appendUserData(thread.pending.collaborators)
      if thread?.collaborators?.length > 0
        appendUserData(thread.collaborators)
      data = 
        researchThread: thread,
        notes: Notes.find
          _threadId: @params._id
        ,
          sort: 
            date: -1
      data
  @route 'researchHome',
    path: '/research'
  @route 'profileEdit',
    path: '/editprofile'

Here is publications.coffee

Meteor.publish 'myResearch', (id) ->
  Research.find({$or: [{_userId: id}, {'collaborators.userId': id}] })


Meteor.publish 'threadNotes', (threadId) ->
  Notes.find({_threadId: threadId})

Meteor.publish 'myBookmarks', (userId) ->
  Bookmarks.find({_userId: userId})

Meteor.publish 'collabUsers', (threadId) ->
  Meteor.users.find({}, {fields: {profile: 1, username: 1}})

Meteor.publish 'notifications', ->
  Notifications.find()

Meteor.publish 'notificationDataCollab', (params) ->
  [
    Meteor.users.find({_id: {$in: params.userIds}}, {fields: {username: 1}})
    Research.find({_id: {$in: params.threadIds}}, {fields: {name: 1}})
  ]

Any advice on how to handle this is appreciated.

Colenecoleopteran answered 2/8, 2014 at 21:25 Comment(0)
L
8

onBeforeAction is run and rerun reactively. You probably want onRun.

Levulose answered 2/8, 2014 at 22:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.