Docpad:通过mongoose回调使用extendTemplateData

时间:2014-02-14 06:07:38

标签: mongodb mongoose docpad

我正在尝试构建一个简单的插件,以便从Mongo获取数据到一个对象,我可以在渲染时迭代它。完整代码在我的project中,但其实质是尝试模拟feedr示例失败。我知道mongoose的东西正在运行,因为控制台日志工作,但获取发送到docpad对象的内容正在打败我

class mongoPlugin extends BasePlugin
    name: 'mongo'

    # Fetch list of Gigs
    getGigsData: (opts) ->
        mongoose.connect ('mongodb://localhost/test')
        db = mongoose.connection;
        db.on 'error', console.error.bind(console, 'connection error:')
        db.once 'open', () -> 
            gigsSchema = mongoose.Schema {
                date : String,
                location : String
            }

            Gigs = mongoose.model 'Gigs', gigsSchema

            Gigs.find {}, (err, gigs) ->
                mongoose.connection.close()
                if err then console.error "db error"
                else 
                    console.dir gigs
                    opts["getGigsData"] = gigs
                    opts.templateData["getGigsData"] = gigs
                    return gigs

    extendTemplateData: (opts) ->
        opts.templateData["getGigsData"] = @getGigsData()

使用node-inspector并通过编辑docpad.coffee触发重新生成,我可以看到opts有一个字段templateData,但是它是空的,与docpad.templateData非常不同,所以我选择了错误的对象插件。我可以看到其他人做了一个在{}中放置名字的技巧,但我不知道那是什么。

在完成插件代码之后,我看到我的数据库数据成为了promise的参数,所以也许这就是它应该与docpad.config.templateData重新集成的地方,但实际上似乎没有发生

1 个答案:

答案 0 :(得分:0)

所以这里的主要问题是我们在同步函数内部执行异步函数getGetsData,即模板引擎。这简单,这是不可能的,因为模板引擎将继续并做它的事情,而同步的东西发生在后台。这只是编写node.js /异步代码的一个问题。

修复此问题非常容易。

  1. opts.templateData["getGigsData"] = @getGigsData()调用getGigsData而没有通过opts,因此当getGigsData尝试并使用opts时,它不能,因此会抛出@getGigsData(opts)一个错误。解决此问题的方法是opts.templateData["getGigsData"] = @getGigsData(opts)

  2. @getGigsData(opts)db.once的返回值分配给模板数据,但是,结果是return gigs调用的结果,因为这将是在那个范围内返回。当您执行(err, gigs) ->时,这实际上是Gigs.find调用getGigsData回调的返回值,而不是getGigsData的返回值。这都是关于范围的。

  3. 由于数据库内容是异步的,我们需要使extendTemplateData: (opts) ->异步。为此,我们将extendTemplateData: (opts,next) ->更改为opts.templateData["getGigsData"] = @getGigsData()以使其异步,并将return @getGigsData(opts,next)更改为getGigsData: (opts) ->

  4. 现在我们有了事件并调用异步。我们现在需要让getGigsData的定义支持它。因此,我们将getGigsData: (opts,next) ->更改为next以接受我们在第3步中定义的完成回调(return gigs)。我们将要做的是,我们将在下一个地方调用{{ 1}},所以我们将return gigs更改为return next()

  5. 现在应该可以了。但是,只需稍加清理,我们就可以通过将if err then console.error "db error"更改为return next(err) if err来更好地进行错误处理。您需要修复缩进,因为我们需要移除else块。

  6. 考虑到这一切,并且应用了更多的清洁工具,你最终会得到这个:

    class mongoPlugin extends BasePlugin
        name: 'mongo'
    
        config:
            hostname: 'mongodb://localhost/test'
    
        # Fetch list of Gigs
        getGigsData: (opts={}, next) ->
            config = @getConfig()
            docpad = @docpad
    
            mongoose.connect(config.hostname)
            db = mongoose.connection
            db.on 'error', (err) ->
                docpad.error(err)  # you may want to change this to `return next(err)`
    
            db.once 'open', -> 
                gigsSchema = mongoose.Schema {
                    date: String,
                    location: String
                }
    
                Gigs = mongoose.model('Gigs', gigsSchema)
    
                Gigs.find {}, (err, gigs) ->
                    mongoose.connection.close()
                    return next(err)  if err
                    return next(null, gigs)
    
            # Chain
            @
    
        extendTemplateData: (opts,next) ->
            @getGigsData null, (err, gigs) ->
                return next(err)  if err
                opts.templateData.gigs = gigs
    
            # Chain
            @