2014-02-26 58 views
3

每次我用新的菜单项更新数据库时,我试图让路由更新一个路由。这是我的悲伤小丑尝试:Express.js动态路由 - 这甚至可能吗?

这里在app.js,我检查菜单数据库和shazaam ...路线在启动在飞行。酷!:

// in app.js // 
var attachDB = function(req, res, next) { 
    req.contentdb = db.content; 
    req.menudb = db.menu; 
    req.app = app; // this is the express() app itself 
    req.page = PageController; 
    next(); 
}; 
db.menu.find({}, function (err, menuitems){ 
    for(var i=0; record = menuitems[i]; i++) { 
     var menuitem = record.menuitem; 
     app.all('/' + menuitem, attachDB, function(req, res, next) { 
      console.log('req from app all route: ',req) 
      PageController.run(menuitem, req, res, next); 
     }); 
    } 

    http.createServer(app).listen(config.port, function() { 
     console.log(
      '\nExpress server listening on port ' + config.port 
     ); 
    }); 
}); 

不是真正的优雅,但它是一种概念证明。现在问题是:当我在Admin.js文件中保存一个新的菜单项时,数据库get被更新,路由器似乎得到更新,但点击带有动态创建的路由的菜单链接后,该请求刚好爆炸

请求中的很多东西似乎都已丢失,我觉得有些基本的东西我不明白路由,回调或者这可能只是错误的解决方案。这里就是负责创建一个新的菜单项,并创造了我的Admin.js文件的新路径的功能看起来像:

// in Admin.js // 
menuItem: function(req, res, callback) { 
    var returnMenuForm = function() { 
     res.render('admin-menuitem', {}, function(err, html) { 
      callback(html); 
     }); 
    }; 
    var reqMenudb = req.menudb, 
     reqContentdb = req.contentdb, 
     reqApp = req.app, 
     reqPage = req.page; 

    if(req.body && req.body.menuitemsubmitted && req.body.menuitemsubmitted === 'yes') { 
     var data = { menuitem: req.body.menuitem }; 
     menuModel.insert(data, function(err) { 
      if (err) { 
       console.log('Whoa there...',err.message); 
       returnMenuForm(); 
      } else { 
       // data is inserted....great. PROBLEM...the routes have not been updated!!! Attempt that mimics what I do in app.js here... 
       reqApp.all('/' + data.menuitem, function(req, res, next) { 
        // the 2 db references below are set with the right values here 
        req.contentdb = reqContentdb; 
        req.menudb = reqMenudb; 
        next(); 
       }, function(req, res, next) { 
        reqPage.run(data.menuitem, req, res, next); 
       }); 

       returnMenuForm(); 
      } 
     }); 
    } else { 
     returnMenuForm(); 
    } 
}, 

在管理部分保存数据的正常工作。如果您控制台登录app.routes,它甚至会显示一条非常酷的新路线。但是,在刷新页面并单击新路由应该工作的链接后,我得到一个未定义的错误。

管理员将数据传递到我的页面控制器:

// in PageController.js // 
module.exports = BaseController.extend({ 
    name: "Page", 
    content: null, 
    run: function(type, req, res, next) { 
     model.setDB(req.contentdb); /* <-- problem here, req.contentdb is undefined which causes me problems when talking to the Page model */ 
     var self = this; 
     this.getContent(type, function() { 
      var v = new View(res, 'inner'); 
      self.navMenu(req, res, function(navMenuMarkup){ 
       self.content.menunav = navMenuMarkup; 
       v.render(self.content); 
      }); 
     }); 
    }, 
    getContent: function(type, callback) { 
     var self = this; 
     this.content = {} 
     model.getlist(function(records) { 
      if(records.length > 0) { 
       self.content = records[0]; 
      } 
      callback(); 
     }, { type: type }); 
    } 

最后,错误的一点是这里的模型

// in Model.js // 
module.exports = function() { 

    return { 
     setDB: function(db) { 
      this.db = db; 
     }, 
     getlist: function(callback, query) { 
      this.db.find(query || {}, function (err, doc) { callback(doc) }); 
     }, 

这里终于看到了“这个”上面的获取列表方法是未定义的,并导致页面被弹出。

如果我重新启动服务器,由于我的动态加载器在app.js中,所有事情都可以再次运行。但是在更新数据库之后没有一些方法可以重新加载路由吗?我的技术在这里不起作用,并且将主应用程序传递给控制器​​是件丑陋的事,因为我正在这里做。

回答

3

我建议两个转变:

  1. 移动此菜单连接东西一个独立的模块。
  2. 当你在它的时候,做一些缓存。

概念证明菜单分贝功能,异步与setTimeout的制作,你会与实际工作DB调用替换它。

// menuitems is cached here in this module. You can make an initial load from db instead. 
var menuitems = []; 
// getting them is simple, always just get the current array. We'll use that. 
var getMenuItems = function() { 
    return menuitems; 
} 

// this executes when we have already inserted - calls the callback 
var addMenuItemHandler = function(newItem, callback) { 
    // validate that it's not empty or that it does not match any of the existing ones 
    menuitems.push(newItem); 
    // remember, push item to local array only after it's added to db without errors 
    callback(); 
} 
// this one accepts a request to add a new menuitem 
var addMenuItem = function(req, res) { 
    var newItem = req.query.newitem; 

    // it will do db insert, or setTimeout in my case 
    setTimeout(function(newItem){ 
     // we also close our request in a callback 
     addMenuItemHandler(newItem, function(){ 
      res.end('Added.'); 
     }); 

    }, 2000); 
}; 

module.exports = { 
    addMenuItem: addMenuItem, 
    getMenuItems: getMenuItems 
} 

所以,现在你有一个模块menuhandler.js。让我们构建它并在我们的应用程序中使用它。

var menuHandler = require('./menuhandler'); 
var app = express(); 
// config, insert middleware etc here 

// first, capture your static routes - the ones before the dynamic ones. 
app.get('/addmenuitem', menuHandler.addMenuItem); 
app.get('/someotherstaticroute', function(req, res) { 
    var menu = menuHandler.getMenuItems(); 
    res.render('someview', {menu: menu}); 
}); 


// now capture everything in your menus. 
app.get('/:routename', function(req, res){ 
    // get current items and check if requested route is in there. 

    var menuitems = menuHandler.getMenuItems(); 
    if(menuitems.indexOf(req.params.routename) !== -1) { 
     res.render('myview', {menu: menuitems}); 
    } else { 
     // if we missed the route, render some default page or whatever. 
    } 
}); 

app.get('/', function(req, res) { 
    // ... 
}); 

现在,你不必去分贝,如果没有新的更新(因为排列的菜单项总是最新的),所以你的初始视图渲染速度更快(对于一个1 DB调用,反正)。

编辑:哦,我刚才看到你的Model.js。这个问题存在着this是指你已返回的对象:

{ 
    setDB: function(db) { 
     this.db = db; 
    }, 
    getlist: function(callback, query) { 
     this.db.find(query || {}, function (err, doc) { callback(doc) }); 
    } 
} 

所以,没有DB默认。而且,由于您在初始页面加载中附加了一些东西到app,您确实得到了一些东西。

但是,在您当前的更新功能中,您将东西附加到新应用程序(reqApp = req.app),所以现在您不是在与原始应用程序交谈,而是在与另一个实例交谈。我认为你的后续请求(更新后)会让范围混淆在一起,因此与实际的最新数据失去联系。

+1

这是代码的一个很好的例子,让我走向正确的方向,组织良好。今天我学到了一个新的窍门。谢谢你,兹拉特科。 –

+1

你的评论是更好的司机回答人们的问题,然后声誉点:) – Zlatko

3

在你的代码中,当你启动你的服务器时,它从菜单db中读取并创建你的路由。当你的菜单改变时,你不会再次从数据库读取数据。

我建议你这样做以下

app.all('*', function(req, res) { 
    //read from your menu db and do the the route management yourself 
}); 
+0

是的,这似乎是一个完美的可行的方式来解决这个问题。我曾考虑过这种策略作为一种选择,但在我看来,应该能够在快速应用程序运行时添加和从路线中删除,而不是通过路线寻找路线。这最终是我想弄明白的。 –

+0

我面临同样的问题,我认为这可能是解决它的可行方法。 – Tokimon