Source codefunction (name, params, actions) {
var self = this;
// params are optional
params = params || {};
// if params arg omitted, second arg may be `actions`
if (typeof params == 'function') {
actions = params;
params = {};
}
params.appendFormat = ('appendFormat' in params) ? params.appendFormat : true;
// If resource uses the path param, it's subroutes should be
// prefixed by path, not the resource's name
// i.e.:
// map.resource('users', {path: ':username'}, function(user) {
// user.resources('posts);
// });
//
// /:username/posts.:format?
// /:username/posts/new.:format?
// etc.
var prefix = params.path ? params.path : name;
// we have bunch of actions here, will create routes for them
var activeRoutes = getActiveRoutes(params);
// but first, create subroutes
if (typeof actions == 'function') {
var oldResource = this.latestResource;
this.latestResource = name;
if (params.singleton) {
this.subroutes(prefix, actions); // singletons don't need to specify an id
} else {
this.subroutes(prefix + '/:' + (singularize(name) || name) + '_id', actions);
}
this.latestResource = oldResource;
}
// now let's walk through action routes
for (var action in activeRoutes) {
(function (action) {
var route = activeRoutes[action].split(/\s+/);
var method = route[0];
var path = route[1];
// append format
if (params.appendFormat !== false) {
if (path == '/') {
path = '.:format?';
} else {
path += '.:format?';
}
}
// middleware logic (backward compatibility)
var middlewareExcept = params.middlewareExcept, skipMiddleware = false;
if (middlewareExcept) {
if (typeof middlewareExcept == 'string') {
middlewareExcept = [middlewareExcept];
}
middlewareExcept.forEach(function (a) {
if (a == action) {
skipMiddleware = true;
}
});
}
// params.path setting allows to override common path component
var effectivePath = (params.path || name) + path;
var controller = params.controller || name;
// and call map.{get|post|update|delete}
// with the path, controller, middleware and options
this[method.toLowerCase()].call(
this,
effectivePath,
controller + '#' + action,
skipMiddleware ? [] : params.middleware,
getParams(action, params)
);
}.bind(this))(action);
}
return this;
// calculate set of routes based on params.only and params.except
function getActiveRoutes(params) {
var activeRoutes = {},
availableRoutes =
{ 'index': 'GET /'
, 'create': 'POST /'
, 'new': 'GET /new'
, 'edit': 'GET /:id/edit'
, 'destroy': 'DELETE /:id'
, 'update': 'PUT /:id'
, 'show': 'GET /:id'
},
availableRoutesSingleton =
{ 'show': 'GET /'
, 'create': 'POST /'
, 'new': 'GET /new'
, 'edit': 'GET /edit'
, 'destroy': 'DELETE /'
, 'update': 'PUT /'
};
if (params.singleton)
availableRoutes = availableRoutesSingleton;
// 1. only
if (params.only) {
if (typeof params.only == 'string') {
params.only = [params.only];
}
params.only.forEach(function (action) {
if (action in availableRoutes) {
activeRoutes[action] = availableRoutes[action];
}
});
}
// 2. except
else if (params.except) {
if (typeof params.except == 'string') {
params.except = [params.except];
}
for (var action in availableRoutes) {
if (params.except.indexOf(action) == -1) {
activeRoutes[action] = availableRoutes[action];
}
}
}
// 3. all
else {
for (var action in availableRoutes) {
activeRoutes[action] = availableRoutes[action];
}
}
return activeRoutes;
}
function getParams(action, params) {
var p = {};
var plural = action === 'index' || action === 'create';
if (params.as) {
p.as = plural ? params.as : (singularize(params.as) || params.as);
p.as = self.urlHelperName(self.globPath + p.as);
if (action === 'new' || action === 'edit') {
p.as = action + '_' + p.as;
}
if (params.suffix && !plural) {
p.as = p.as + '_' + (singularize(params.suffix) || params.suffix);
}
}
if (params.path && !p.as) {
var aname = plural ? name : (singularize(name) || name);
aname = self.urlHelperName(self.globPath + aname);
p.as = action === 'new' || action === 'edit' ? action + '_' + aname : aname;
}
if ('state' in params) {
p.state = params.state;
}
return p;
}
};