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

随声附和 提交于 2019-11-28 08:29:52

问题


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.


回答1:


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



来源:https://stackoverflow.com/questions/25099549/meteor-why-is-iron-routers-onbeforeaction-called-multiple-times

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!