【问题标题】:How to create a normal sails model without being in the models folder如何在不位于模型文件夹中的情况下创建普通帆模型
【发布时间】:2014-01-31 20:44:50
【问题描述】:

所以,

我正在为我的应用程序实现一个插件 api,插件可以有自己的模型,想象一下。

SimplePlugin = {
    pluginName: 'simple',

    pluginConfig: {},

    SimpleModel: {

        attributes: {
            name: 'string'
        }

    } 

}

因此,我需要能够在需要时创建带有函数的“一次性”模型,它需要具有与其他模型完全相同的功能,以便您自动获取 /simplePlugin/:id 之类的 URL 用于 find ..等等

谢谢

【问题讨论】:

  • sails.models.yourmodel
  • @gorelativesails 怎么会知道呢?能够设置模型...
  • 您使用的是 v0.9.x 还是 v0.10?如何使用自定义钩子实现插件 api?

标签: javascript node.js models sails.js waterline


【解决方案1】:

在项目的当前状态下,你想要做的事情并不容易,而且有点混乱。我指的是 v0.10 版本。你要做的就是

  1. SimplePlugin.SimpleModel 中的模型定义注入sails.models
  2. 为带有_config: { rest: true }的模型注入一个虚拟控制器

请注意,我发布的代码示例取自我正在处理的自定义 Sails 挂钩,并假定访问 sails 以及在 Sails 初始化的 loadHooks 阶段/@987654328 之前执行的代码示例@phase(比较:lib/app/load.js)。

1。注入模型定义

按照 Sails v0.10 中的 hints in the orm hook,您必须:

  • 获取api中定义的模型和适配器,将你的新模型合并到字典中
  • 通过sails.hooks.orm.normalizeModelDef 规范化模型定义
  • 将标准化模型定义加载到 Waterline 中
  • 通过teardown卸载现有的适配器连接
  • 重新初始化水线
  • 通过sails.hooks.orm.prepareModels(以前:sails.hooks.orm.exposeModels,更改为:8d96895662)将初始化的 Waterline 集合公开给帆和全局范围

因为您必须重新初始化 Waterline 并重新加载所有模型定义,所以我建议您收集所有模型定义以进行注入并将它们传递给注入函数一次。下面的示例代码反映了这一点。

...

function injectPluginModels(pluginModels, cb) {
  // copy sails/lib/hooks/orm/loadUserModules to make it accessible here
  var loadUserModelsAndAdapters = require('./loadUserModules')(sails);

  async.auto({
    // 1. load api/models, api/adapters
    _loadModules: loadUserModelsAndAdapters,

    // 2. Merge additional models,  3. normalize model definitions
    modelDefs: ['_loadModules', function(next){
      _.each(additionModels, function(aditionModel) {
         _.merge(sails.models, additionalModel);
      });

      _.each(sails.models, sails.hooks.orm.normalizeModelDef);
      next(null, sails.models);
    }],

    // 4. Load models into waterline, 5. tear down connections, 6. reinitialize waterline
    instantiatedCollections: ['modelDefs', function(next, stack){
      var modelDefs = stack.modelDefs;

      var waterline = new Waterline();
      _.each(modelDefs, function(modelDef, modelID){
        waterline.loadCollection(Waterline.Collection.extend(modelDef));
      });

      var connections = {};

      _.each(sails.adapters, function(adapter, adapterKey) {
        _.each(sails.config.connections, function(connection, connectionKey) {
          if (adapterKey !== connection.adapter) return;
          connections[connectionKey] = connection;
        });
      });

      var toTearDown = [];

      _.each(connections, function(connection, connectionKey) {
        toTearDown.push({ adapter: connection.adapter, connection: connectionKey });
      });

      async.each(toTearDown, function(tear, callback) {
         sails.adapters[tear.adapter].teardown(tear.connection, callback);
      }, function(){
         waterline.initialize({
           adapters: sails.adapters,
           connections: connections
         }, next)
      });
    }],

    // 7. Expose initialized models to global scope and sails
    _prepareModels: ['instantiatedCollections', sails.hooks.orm.prepareModels]

  }, cb);
};

...

将允许您:

// Read your plugins
...

var pluginModels = // Get all the plugin models
injectPluginModels(pluginModels, function(){
  // Plugin models now available via global[pluginModel.globalId] and sails.models[pluginModel.identity]
});

2。注入控制器

对于应该通过蓝图方法公开的每个模型,您必须:

  • 创建具有匹配标识和启用蓝图的控制器定义
  • 将控制器保存到sails.controllers[controllerId]
  • 将控制器保存到sails.hooks.controllers.middleware[controllerId]

Sails MiddlewareRegistry 将自动拾取在这些对象中找到的控制器。

function mountBlueprintsForModels(pluginModels) {
  _.each(pluginModels, function(pluginModel){
    var controller = _.cloneDeep(pluginModel);
    controller._config = { rest: true };

    var controllerId = pluginModel.identity;

    if (!_.isObject(sails.controllers[controllerId])) {
      sails.controllers[controllerId] = controller;
    }

    if (!_.isObject(sails.hooks.controllers.middleware[controllerId])) {
      sails.hooks.controllers.middleware[controllerId] = controller;
    }
  });
}

3。在行动

// E.g. in /api/hooks/plugins/index.js
/*
 * Module dependencies
 */

var async = require('async'),
    _ = require('lodash'),
    waterline = require('waterline');

module.exports = function(sails) {

  // injectPluginModels and mountBlueprintsForModels defined here
  ...

  return {

    initialize: function(cb) {
      sails.after('hook:orm:loaded', function() {
        yourNiftyPluginLoader(function(err, plugins) {
          // assuming plugin.models holds array of models for this plugin
          // customize for your use case
          var pluginModels = _.pluck(plugins, 'models');
          injectPluginModels(pluginModels, cb);
          mountBlueprintsForModels(pluginModels);
        });
      });
    }

  }

}

【讨论】:

  • 感谢您的回答:)
  • 绝妙的答案!唯一让我感到困惑的是yourNiftyPluginLoader 函数。这是从哪里来的?
  • yourNiftyPluginLoader 也让我很困惑,直到那时我才意识到它只是负责从文件系统加载插件模型/控制器/等的函数。您可以使用 include-all、sails-build-dictionary 或 require-all 来帮助您。
  • 很好的答案@marionebl。
【解决方案2】:

编辑:由于集合在初始化时分配给连接,因此无法完全工作。

似乎有更好的解决方案,只需 3 行代码,无需断开/重新连接数据库。我刚刚研究了Waterline的源代码(见https://github.com/balderdashy/waterline/blob/master/lib/waterline.js#L109)。可以这样做:

var Waterline = require('waterline');

// Other dependencies
var Schema = require('waterline-schema');
var CollectionLoader = require('waterline/lib/waterline/collection/loader');

var orm = new Waterline();

var config = {
    // Setup Adapters
    // Creates named adapters that have have been required
    adapters: {
        'default': 'mongo',
        mongo: require('sails-mongo')
    },

    // Build Connections Config
    // Setup connections using the named adapter configs
    connections: {
        'default': {
            adapter: 'mongo',
            url: 'mongodb://localhost:27017/sausage'
        }
    }
};

orm.initialize(config, function(err, data) {
    if (err) {
        throw err;
    }

    // ORM initialized, let's add another model dynamically
    var User = Waterline.Collection.extend({
       identity: 'user',
        connection: 'default',

        attributes: {
            first_name: 'string',
            last_name: 'string'
        }
    });
    orm.loadCollection(User);

    var defaults = config.defaults || {};

    // This is where the magic happens
    var loader = new CollectionLoader(User, orm.connections, defaults);
    var collection = loader.initialize(orm);
    orm.collections[collection.identity.toLowerCase()] = collection;

    // Done! You can now use orm.collections.user :-D
});

【讨论】:

    【解决方案3】:

    在 v0.12 中,sails.hooks.orm.normalizeModelDef 不再存在。 sails/lib/hooks/orm/loadUserModules 也去了sails-hook-orm npm 模块,不再是sails 的一部分。

    【讨论】:

      【解决方案4】:

      试试这个: “从指定目录加载模型、控制器、服务、策略和配置,并将它们注入到主 Sails 应用程序中。”

      https://github.com/leeroybrun/sails-util-mvcsloader

      【讨论】:

        【解决方案5】:

        惊讶的风帆在 2018 年不支持这一点:我继续使用叉子(@eyn 回答)上面的包,更新适用于风帆 v1.x.x。

        https://github.com/emahuni/sails-util-micro-apps

        我把它改成了那个因为我在那个包里改变了很多东西。我不想只加载模型和控制器,而是希望它加载整个应用程序,用于微服务架构的微应用程序。这样您就可以使用可重用的 api 代码制作迷你应用程序,这些应用程序可以连接在一起形成一个大型应用程序。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多