Использование слагов в URL в CRUD в MEANJS

Мне нужно было использовать слаги в URL-адресе вместо идентификатора статьи, поэтому я изменил пару вещей в примере статей, приведенном с помощью meanjs, но у меня есть проблема: я могу перечислять, просматривать и редактировать, но я не могу создавать новые. Я не знаком со стеком MEAN, поэтому вполне возможно, что в моих модификациях что-то не так, но я могу придумать, как заставить его работать.

Слаг генерируется из заголовка при создании статьи. Я бы тоже хотел, чтобы меня редактировали, но если я также добавлю поле slug для редактирования, функция редактирования тоже перестанет работать...

Код взят из ветки 0.4, использующей вертикальные модули.

В статьях.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'
            }
        });
    }
]);

Функция создания начинает работать, но функция редактирования останавливается... -.-

Любая помощь будет оценена. Спасибо

Это мой articles.server.routes.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);
};

Это мой articles.client.service.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'
            }
        });
    }
]);

Это мой articles.client.controller.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
            });
        };

    }
]);

Это мой articles.server.controller.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();
    });
};

person codiaf    schedule 26.12.2014    source источник
comment
В чем вопрос, какой код ошибки или ответа вы получаете, когда пытаетесь обновить или создать статью?   -  person teleaziz    schedule 30.12.2014
comment
Я получаю это на консоли терминала: Error: Failed to load article asdf это сообщение, напечатанное функцией articleBySlug в article.server.controller.js. Полный вывод ошибки здесь: pastebin.com/wwxKFi5G   -  person codiaf    schedule 30.12.2014


Ответы (1)


Я клонировал ветку 0.4.0 и вот что я сделал, чтобы маршрутизация с помощью slug работала должным образом во всех сценариях.

1- Добавьте ярлык в схему статьи и убедитесь, что он уникален 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- Добавьте метод в контроллер статей для поиска статей по слагу (или вообще что-нибудь в 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- Добавьте в сервис статей метод для получения статей по слагу:

    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- Наконец, рефакторинг обновления и создание, чтобы включить слаг (в контроллере статей):

    $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;
        });
    };
person teleaziz    schedule 30.12.2014
comment
Да уже есть. Если я изменю переменную articleSlug в article.client.service.js, я смогу создать без проблем, но редактирование и удаление функций перестанут работать. - person codiaf; 30.12.2014
comment
Создание статьи должно работать в любом случае, потому что оно вообще не зависит от параметра articleSlug. Я бы оставил articleSlug: @slug в сервисном файле и исследовал проблему на бэкенде. - person teleaziz; 30.12.2014