Skip to content

Commit

Permalink
Updates to blueprints hook:
Browse files Browse the repository at this point in the history
* Drop support for custom blueprints
* Drop support for `{blueprint: 'find', model: 'user'}` route target syntax
* Rename "registerModelActions" to "registerActions" to work with sails.loadActions
* Only register actions if ORM hook is active
* Re-bind shadow routes _every_ time `router:after` event is emitted
  • Loading branch information
sgress454 committed Sep 27, 2016
1 parent da0ed6f commit 0fd4362
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 152 deletions.
75 changes: 16 additions & 59 deletions lib/hooks/blueprints/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,27 +118,25 @@ module.exports = function(sails) {
hook = this;

// Register route syntax for binding blueprints directly.
// This is deprecated, so onRoute currently just logs a warning.
sails.on('route:typeUnknown', onRoute);

// Register actions when the ORM hook loads or reloads.
sails.after('hook:orm:loaded', hook.registerModelActions);
sails.after('hook:orm:reloaded', hook.registerModelActions);
// Wait until after user routes have been bound to bind our
// own "shadow routes" (action routes, RESTful routes,
// shortcut routes and index routes).
sails.on('router:after', hook.bindShadowRoutes);

// Set up listener to bind shadow routes when the time is right.
//
// Always wait until after router has bound static routes.
// If policies hook is enabled, also wait until policies are bound.
// If orm hook is enabled, also wait until models are known.
// If controllers hook is enabled, also wait until controllers are known.
var eventsToWaitFor = [];
eventsToWaitFor.push('router:after');
// If the ORM hook is active, wait for it to load, then create actions
// for each model.
if (sails.hooks.orm) {
eventsToWaitFor.push('hook:orm:loaded');
sails.after('hook:orm:loaded', function() {
hook.registerActions(cb);
});
}
// Otherwise we're done!
else {
return cb();
}
sails.after(eventsToWaitFor, hook.bindShadowRoutes);

// Load blueprint middleware and continue.
this.loadModules(cb);
},


Expand Down Expand Up @@ -386,49 +384,7 @@ module.exports = function(sails) {

},

/**
* (Re)load middleware.
*
* First, built-in blueprint actions in core Sails will be loaded.
* Then, we'll attempt to load any custom blueprint definitions from
* the user app using moduleloader.
*
* @api private
*/

loadModules: function (cb) {

var hook = this;

sails.log.verbose('Loading blueprint actions...');

// Clear out the internal actions dictionary.
hook._actions = {};

// Load actions from the api/blueprints folder.
includeAll.optional({
dirname: sails.config.paths.blueprints,
filter: new RegExp('(.+)\\..+$'),
useGlobalIdForKeyName: true
}, function modulesLoaded (err, modules) {
if (err) { return cb(err); }

// Start off w/ the built-in blueprint actions (generic CRUD logic)
// (see BlueprintController definition at top of file) and merge in
// custom overrides from the user app.
_.extend(hook._actions, BlueprintController, modules);

// Add _middlewareType keys to the functions, for debugging
_.each(hook._actions, function(fn, key) {
fn._middlewareType = 'BLUEPRINT: '+fn.name || key;
});

return cb(err);

});
},

registerModelActions: function() {
registerActions: function(cb) {
// Loop through all of the loaded models and add actions for each.
_.each(_.keys(sails.models), function(modelIdentity) {
sails.registerAction(BlueprintController.create, modelIdentity + '.create');
Expand All @@ -440,6 +396,7 @@ module.exports = function(sails) {
sails.registerAction(BlueprintController.add, modelIdentity + '.add');
sails.registerAction(BlueprintController.remove, modelIdentity + '.remove');
});
return cb();
}

};
Expand Down
110 changes: 17 additions & 93 deletions lib/hooks/blueprints/onRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,107 +34,31 @@ module.exports = function(sails) {
verb = route.verb,
options = route.options;

// Support referencing blueprints in explicit routes
// (`{ blueprint: 'create' }` et. al.)
if (
_.isObject(target) &&
!_.isFunction(target) &&
!_.isArray(target) &&
_.isString(target.blueprint)) {

// On a match, merge leftover items in the target object into route options:
options = _.merge(options, _.omit(target, 'blueprint'));
// Note: this (^) could be moved up into lib/router/bind.js, since its
// only pertinent for core options such as `skipAssets`. There would need
// to be changes in other hooks as well.

return bindBlueprintAction(path, target.blueprint, verb, options);
if (_.isFunction(target)) {
throw new Error('Consistency violation: route target is a function, but is being handled by blueprint hook instead of Sails router!');
}

// Ignore unknown route syntax
// If it needs to be understood by another hook, the hook would have also received
// the typeUnknown event, so we're done.
return;
};



/**
* Bind explicit route to a blueprint action.
*
* @param {[type]} path [description]
* @param {[type]} blueprintActionID [description]
* @param {[type]} verb [description]
* @param {[type]} options [description]
* @return {[type]} [description]
* @api private
*/
function bindBlueprintAction(path, blueprintActionID, verb, options) {

// Look up appropriate blueprint action and make sure it exists
var blueprint = sails.middleware.blueprints[blueprintActionID];

// If a 'blueprint' was specified, but it doesn't exist, warn the user and ignore it.
if (!(blueprint && _.isFunction(blueprint))) {
sails.log.error(
blueprintActionID,
':: Ignoring attempt to bind route (' + path + ') to unknown blueprint action (`' + blueprintActionID + '`).'
);
return;
if (_.isArray(target)) {
throw new Error('Consistency violation: route target is an array, but is being handled by blueprint hook instead of Sails router!');
}

// If a model wasn't provided with the options, try and guess it
if (!options.model) {
var matches = path.match(/^\/(\w+).*$/);
if (matches && matches[1] && sails.models[matches[1]]) {
options.model = matches[1];
} else {
sails.log.error(
blueprintActionID,
':: Ignoring attempt to bind route (' + path + ') to blueprint action (`' + blueprintActionID + '`), but no valid model was specified and we couldn\'t guess one based on the path.'
);
return;
}
if (!_.isObject(target)) {
throw new Error('Consistency violation: route target is a ' + typeof(target) + ', but is being handled by blueprint hook instead of Sails router!');
}

// If associations weren't provided with the options, try and get them
if (!options.associations) {
options = _.merge({
associations: _.cloneDeep(sails.models[options.model].associations)
}, options);
}
// Otherwise make sure it's an array of strings of valid association aliases
else {
options.associations = options.associations.map(function(alias) {
if (!_.isString(alias)) {
sails.log.error(
blueprintActionID,
':: Ignoring invalid association option for ' + path + '.'
);
return;
}
var association;
if (!(association = _.findWhere(sails.models[options.model].associations, {
alias: alias
}))) {
sails.log.error(
blueprintActionID,
':: Ignoring invalid association option `' + alias + '` for ' + path + '.'
);
return;
}
return association;
});
}
// Support referencing blueprints in explicit routes
// (`{ blueprint: 'create' }` et. al.)
if (!_.isUndefined(target.blueprint)) {

// If "populate" wasn't provided in the options, use the default
if (_.isUndefined(options.populate)) {
options.populate = sails.config.blueprints.populate;
}
var errMsg = 'The `blueprint` route target syntax is no longer supported.';
if (_.isString(target.blueprint) && _.isString(target.model)) {
errMsg = ' Use {action: \'' + target.model.toLowerCase() + '.' + target.blueprint + '\'} instead!';
}
sails.log.error(errMsg);
return;

sails.router.bind(path, blueprint, verb, options);
}

return;
}
};

};

0 comments on commit 0fd4362

Please sign in to comment.