在 MEANJS 的 CRUD 中的 URL 中使用 slugs



我需要在 URL 中使用 slugs 而不是文章 ID,所以我在 meanjs 给出的文章示例中更改了一些东西,但我有一个问题,我可以列出、查看和编辑,但我无法创建新的。我不熟悉 MEAN 堆栈,所以我很可能在我的修改中出现了一些非常错误的地方,但我可以想到一种让它工作的方法。

辅助信息域是在创建文章时从标题生成的。我也想被编辑,但是如果我把要编辑的 slug 字段也放进去,编辑功能也会停止工作......

代码来自使用垂直模块的 meanjs 的 0.4 分支。

在 articles.client.service 中.js如果我更改:

angular.module('articles').factory('Articles', ['$resource',
    function($resource) {
        return $resource('api/articles/:articleSlug', {
            articleSlug: '@slug'
        }, {
            update: {
                method: 'PUT'
            }
        });
    }
]);

为:

angular.module('articles').factory('Articles', ['$resource',
    function($resource) {
        return $resource('api/articles/:articleSlug', {
            articleSlug: '@_id'
        }, {
            update: {
                method: 'PUT'
            }
        });
    }
]);

创建功能开始工作,但编辑功能停止... -.-

任何帮助将不胜感激。谢谢

这是我的文章.服务器.路由.js

'use strict';
/**
 * Module dependencies.
 */
var articlesPolicy = require('../policies/articles.server.policy'),
    articles = require('../controllers/articles.server.controller');
module.exports = function(app) {
    // Articles collection routes
    app.route('/api/articles').all(articlesPolicy.isAllowed)
        .get(articles.list)
        .post(articles.create);
    // Single article routes
    app.route('/api/articles/:articleSlug').all(articlesPolicy.isAllowed)
        .get(articles.read)
        .put(articles.update)
        .delete(articles.delete);
    // Finish by binding the article middleware
    app.param('articleSlug', articles.articleBySlug);
};

这是我的文章.客户端.服务.js

'use strict';
//Articles service used for communicating with the articles REST endpoints
angular.module('articles').factory('Articles', ['$resource',
    function($resource) {
        return $resource('api/articles/:articleSlug', {
            articleSlug: '@slug'
        }, {
            update: {
                method: 'PUT'
            }
        });
    }
]);

这是我的文章.客户端.控制器.js

'use strict';
angular.module('articles').controller('ArticlesController', ['$scope', '$stateParams', '$location', 'Authentication', 'Articles',
    function($scope, $stateParams, $location, Authentication, Articles) {
        $scope.authentication = Authentication;
        $scope.create = function() {
            var article = new Articles({
                slug: this.title.toLowerCase().replace(/ /g, '-'),
                title: this.title,
                content: this.content
            });
            article.$save(function(response) {
                $location.path('articles/' + response.slug);
                $scope.slug = '';
                $scope.title = '';
                $scope.content = '';
            }, function(errorResponse) {
                $scope.error = errorResponse.data.message;
            });
        };
        $scope.remove = function(article) {
            if (article) {
                article.$remove();
                for (var i in $scope.articles) {
                    if ($scope.articles[i] === article) {
                        $scope.articles.splice(i, 1);
                    }
                }
            } else {
                $scope.article.$remove(function() {
                    $location.path('articles');
                });
            }
        };
        $scope.update = function() {
            var article = $scope.article;
            article.$update(function() {
                $location.path('articles/' + article.slug);
            }, function(errorResponse) {
                $scope.error = errorResponse.data.message;
            });
        };
        $scope.find = function() {
            $scope.articles = Articles.query();
        };
        $scope.findOne = function() {
            $scope.article = Articles.get({
                articleSlug: $stateParams.articleSlug
            });
        };
    }
]);

这是我的文章.服务器.控制器.js

'use strict';
/**
 * Module dependencies.
 */
var _ = require('lodash'),
    path = require('path'),
    mongoose = require('mongoose'),
    Article = mongoose.model('Article'),
    errorHandler = require(path.resolve('./modules/core/server/controllers/errors.server.controller'));
/**
 * Create a article
 */
exports.create = function(req, res) {
    var article = new Article(req.body);
    article.user = req.user;
    article.save(function(err) {
        if (err) {
            return res.status(400).send({
                message: errorHandler.getErrorMessage(err)
            });
        } else {
            res.json(article);
        }
    });
};
/**
 * Show the current article
 */
exports.read = function(req, res) {
    res.json(req.article);
};
/**
 * Update a article
 */
exports.update = function(req, res) {
    var article = req.article;
    article.title = req.body.title;
    article.content = req.body.content;
    article.save(function(err) {
        if (err) {
            return res.status(400).send({
                message: errorHandler.getErrorMessage(err)
            });
        } else {
            res.json(article);
        }
    });
};
/**
 * Delete an article
 */
exports.delete = function(req, res) {
    var article = req.article;
    article.remove(function(err) {
        if (err) {
            return res.status(400).send({
                message: errorHandler.getErrorMessage(err)
            });
        } else {
            res.json(article);
        }
    });
};
/**
 * List of Articles
 */
exports.list = function(req, res) {
    Article.find().sort('-created').populate('user', 'displayName').exec(function(err, articles) {
        if (err) {
            return res.status(400).send({
                message: errorHandler.getErrorMessage(err)
            });
        } else {
            res.json(articles);
        }
    });
};
/**
 * Article middleware
 */
exports.articleBySlug = function(req, res, next, slug) {
    Article.findOne({'slug': slug}).populate('user', 'displayName').exec(function(err, article) {
        if (err) return next(err);
        if (!article) return next(new Error('Failed to load article ' + slug));
        req.article = article;
        next();
    });
};

我克隆了 0.4.0 分支,这是我所做的,以使 slug 路由在所有情况下都能正常工作。

1-将 slug 添加到文章架构并确保其唯一article.server.model.js

slug: {
    type: String,
    default: '',
    trim: true,
    unique: true,
    required: 'Slug cannot be blank'
}

2-重构文章控制器中的更新方法以包含 slug:

  exports.update = function(req, res) {
      var article = req.article;
      article = _.extend(article , req.body);
      article.save(function(err) {
          if (err) {
              return res.status(400).send({
                  message: errorHandler.getErrorMessage(err)
              });
          } else {
              res.json(article);
          }
      });
  };

3-向文章控制器添加一个方法,以通过slug(或req.query中的任何内容)查找文章

exports.readBySlug = function(req , res){
    Article.findOne(req.query).populate('user',
    'displayName').exec(function(err, article) {
    if (err) {
        return res.status(400).send({
            message: errorHandler.getErrorMessage(err)
        });
        } else {
        res.json(article);
        }
    });
};

3-然后添加一个路由以指向该方法(确保在路由配置的开头或至少在更新之前添加路由,删除路由)

app.route('/api/articles/read-slug').get(articlesPolicy.isAllowed ,
    articles.readBySlug);

4-更改策略以允许GET到该路由,在文章中策略:

exports.invokeRolesPolicies = function() {
    acl.allow([{
        roles: ['admin'],
        allows: [{
            resources: '/api/articles',
            permissions: '*'
        }, {
            resources: '/api/articles/:articleId',
            permissions: '*'
        }]
    }, {
        roles: ['user'],
        allows: [{
            resources: '/api/articles',
            permissions: ['get', 'post']
        }, {
            resources: '/api/articles/:articleId',
            permissions: ['get']
        }]
    }, {
        roles: ['guest'],
        allows: [{
            resources: '/api/articles',
            permissions: ['get']
        }, {
            resources: '/api/articles/:articleId',
            permissions: ['get']
        }]
    }, {
        roles: ['admin','user','guest'],
        allows: [{
            resources: '/api/articles/read-slug',
            permissions: ['get']
        }]
    }]);
};

在前端:

1-更改文章路由中的路由以使用slug而不是id:

    state('articles.view', {
        url: '/:articleSlug',
        templateUrl: 'modules/articles/views/view-article.client.view.html'
    }).
    state('articles.edit', {
        url: '/:articleSlug/edit',
        templateUrl: 'modules/articles/views/edit-article.client.view.html'
    });

2-在视图中更改链接以反映路线更改article.view({articleSlug: article.slug}article.edit相同

3-向文章服务添加一个方法,以通过 slug 获取文章:

    return $resource('api/articles/:articleId/:controller', {
        articleId: '@_id'
    }, {
        update: {
            method: 'PUT'
        } ,
        getBySlug: {
            method: 'GET',
            params: {
              controller: 'read-slug'
            }
      }
    });

4-重构文章控制器中的findOne方法,以使用我们刚刚定义的方法(在文章控制器中):

    $scope.findOne = function() {
        $scope.article = Articles.getBySlug({
            slug: $stateParams.articleSlug
        });

5-最后重构更新并创建以包含 slug(在文章控制器中):

    $scope.update = function() {
        var article = $scope.article;
        article.slug = article.title.toLowerCase().replace(/ /g, '-');
      console.log(article);
        article.$update(function() {
            $location.path('articles/' + article.slug);
        }, function(errorResponse) {
            $scope.error = errorResponse.data.message;
        });
    };

    $scope.create = function() {
        var article = new Articles({
            slug: this.title.toLowerCase().replace(/ /g, '-'),
            title: this.title,
            content: this.content
        });
        article.$save(function(response) {
            $location.path('articles/' + response.slug);
            $scope.title = '';
            $scope.content = '';
        }, function(errorResponse) {
            $scope.error = errorResponse.data.message;
        });
    };

最新更新