Sails REST API и MySQL: TypeError: Model.create (…) .meta не является функцией

0

Я пытаюсь настроить REST API на цифровой VPS Ubuntu 16.04. Я сталкиваюсь с этой ошибкой "TypeError: Model.create(...). Meta не является функцией". После проверки трассировки стека (см. Ниже) функция на самом деле существует.

Несколько вещей, чтобы отметить:

1) Я успешно смог выполнить команду "подтяжка парусов", которая создала "testauthdb" вместе со своей связанной схемой (показано ниже)

2) Используя почтальон (показано ниже), я смог успешно ударить API на удаленном сервере, но он возвратил 500 ошибок с трассировкой стека (показано ниже).

3) Я пробовал несколько способов обновления всех пакетов (@beta, @latest), очистка кеша npm, переустановка узлов node_modules, перезапуск сервера nginx, полное удаление и повторная установка проекта, команда обновления паруса и т.д.

4) https://github.com/balderdashy/sails/issues/4177, была аналогичной проблемой, но они использовали mongodb и mongoose. Я пробовал использовать паруса-mysql @beta и sails-mysql @latest без такой удачи.

5) Отсутствие синтаксических ошибок, обнаруженных компилятором, так что любые небольшие ошибки, которые вы можете увидеть в этом документе, где, скорее всего, проблемы с переводом. Единственная реальная ошибка, на мой взгляд, такова, что она указана в трассировке заголовка/стека.

Любое руководство было бы высоко оценено, я потратил много времени, пытаясь понять эту ошибку.

Версии
узел -v: 9.10.1
npm -v: 5.8.0
паруса -v: 1.0.0

package.json

    {
  "name": "blah",
  "private": true,
  "version": "0.0.0",
  "description": "a Sails application",
  "keywords": [],
  "dependencies": {
    "@sailshq/connect-redis": "^3.2.1",
    "@sailshq/lodash": "^3.10.2",
    "@sailshq/socket.io-redis": "^5.2.0",
    "@sailshq/upgrade": "^1.0.9",
    "ajv": "^6.4.0",
    "async": "^2.6.0",
    "bcryptjs": "^2.4.3",
    "coffeescript": "^2.2.4",
    "grunt": "1.0.1",
    "jsonwebtoken": "^8.2.0",
    "lodash": "^4.17.5",
    "sails": "^1.0.0",
    "sails-hook-grunt": "^3.0.2",
    "sails-hook-orm": "^2.0.0",
    "sails-hook-sockets": "^1.5.2",
    "sails-hook-validation": "^0.4.7",
    "sails-mysql": "^1.0.0",
    "sprint-js": "^0.1.0",
    "waterline": "^0.13.3"
  },
  "devDependencies": {
    "@sailshq/eslint": "^4.19.3"
  },
  "scripts": {
    "start": "NODE_ENV=production node app.js",
    "test": "npm run lint && npm run custom-tests && echo 'Done.'",
    "lint": "eslint . --max-warnings=0 --report-unused-disable-directives && echo 'âœ"  Your .js files look good.'",
    "custom-tests": "echo \"(No other custom tests yet.)\" && echo"
  },
  "main": "app.js",
  "repository": {
    "type": "git",
    "url": "git://github.com/root/dwms-api.git"
  },
  "author": "root",
  "license": "",
  "engines": {
    "node": ">=9.10"
  }
}

API/контроллер/UserController.js

var jwt = require("jsonwebtoken");
var bcrypt = require("bcryptjs");

module.exports = {
  /**
   * this is used to authenticate user to our api using either email and password
   * POST /login
   * @param req
   * @param res
   */
  login: function (req, res) {

    /**
     * this is param checking if they are provided
     */
    if (!_.has(req.body, 'email') || !_.has(req.body, 'password')) {
      return res.serverError("No field should be empty.");
    }

    /**
     * check if the username matches any email or phoneNumber
     */
    User.findOne({
      email: req.body.email
    }).exec(function callback(err, user) {
      if (err) return res.serverError(err);

      if (!user) return res.serverError("User not found, please sign up.");


      //check password
      bcrypt.compare(req.body.password, user.password, function (error, matched) {
        if (error) return res.serverError(error);

        if (!matched) return res.serverError("Invalid password.");

        //save the date the token was generated for already inside toJSON()

        var token = jwt.sign(user.toJSON(), "this is my secret key", {
          expiresIn: '10m'
        });

        //return the token here
        res.ok(token);
      });

    });
  },

  /**
   * this is used to request for another token when the other token is about
   * expiring so for next request call the token can be validated as true
   * GET /token
   * @param req
   * @param res
   */
  token: function (req, res) {
    User.findOne(req.user.id).exec(function callback(error, user) {
      if (error) return res.serverError(error);
      if (!user) return res.serverError("User not found");

      var token = jwt.sign(user.toJSON(), "this is my secret key", {
        expiresIn: '10m'
      });
        res.ok(token);
      });
    }
};

API/модели /Users.js

var bcrypt = require("bcryptjs");

module.exports = {

  attributes: {
    name: {
      type: 'string',
      required: true
    },
    roles: {
      type: 'string',
      defaultsTo: "DEFAULT_USER"
          },
    email: {
      type: 'string',
      unique: true,
      required: true
    },
    password: {
      type: 'string',
      required: true
    },
    lastlogout: {
      type:'string'
    },
  },

   //attributes methods
  customToJSON: function() {
     return _.omit(this, ['password'])
    },

  /**
   * this holds our validation message by
   * sails-hook-validation dependency
   */
  validationMessages: { //hand for i18n & l10n
    names: {
      required: 'Name is required'
    },
    email: {
      email: 'Provide valid email address',
      required: 'Email is required',
      unique: 'This email is already existing'
    },
    password: {
      required: 'Password is required'
    }
  },

  /**
   * this is called so we can create our password hash for us
   *
   * before saving
   * @param values
   * @param cb
   */
  beforeCreate: function(user, cb){
    bcrypt.genSalt(10, function(err, salt){
      bcrypt.hash(user.password, salt, null, function(err, hash){
        if(err) return cb(err);
        user.password = hash;
        return cb();
      });
    });
  }
};

конфиг /model.js

module.exports.models = {
  /***************************************************************************
  *                                                                          *
  * Your app default connection. i.e. the name of one of your app        *
  * connections (see 'config/connections.js')                                *
  *                                                                          *
  ***************************************************************************/

  /***************************************************************************
  *                                                                          *
  * Whether the '.create()' and '.update()' model methods should ignore      *
  * (and refuse to persist) unrecognized data-- i.e. properties other than   *
  * those explicitly defined by attributes in the model definition.          *
  *                                                                          *
  * To ease future maintenance of your code base, it is usually a good idea  *
  * to set this to 'true'.                                                   *
  *                                                                          *
  * > Note that 'schema: false' is not supported by every database.          *
  * > For example, if you are using a SQL database, then relevant models     *
  * > are always effectively 'schema: true'.  And if no 'schema' setting is  *
  * > provided whatsoever, the behavior is left up to the database adapter.  *
  * >                                                                        *
  * > For more info, see:                                                    *
  * > https://sailsjs.com/docs/concepts/orm/model-settings#?schema           *
  *                                                                          *
  ***************************************************************************/

   schema: true,


  /***************************************************************************
  *                                                                          *
  * How and whether Sails will attempt to automatically rebuild the          *
  * tables/collections/etc. in your schema.                                  *
  *                                                                          *
  * > Note that, when running in a production environment, this will be      *
  * > automatically set to 'migrate: 'safe'', no matter what you configure   *
  * > here.  This is a failsafe to prevent Sails from accidentally running   *
  * > auto-migrations on your production database.                           *
  * >                                                                        *
  * > For more info, see:                                                    *
  * > https://sailsjs.com/docs/concepts/orm/model-settings#?migrate          *
  *                                                                          *
  ***************************************************************************/

   migrate: 'alter',


  /***************************************************************************
  *                                                                          *
  * Base attributes that are included in all of your models by default.      *
  * By convention, this is your primary key attribute ('id'), as well as two *
  * other timestamp attributes for tracking when records were last created   *
  * or updated.                                                              *
  *                                                                          *
  * > For more info, see:                                                    *
  * > https://sailsjs.com/docs/concepts/orm/model-settings#?attributes       *
  *                                                                          *
  ***************************************************************************/

  attributes: {
    id: { type: 'number', autoIncrement: true, },
    createdAt: { type: 'string', autoCreatedAt: true, },
    updatedAt: { type: 'string', autoUpdatedAt: true, },
  },


  /******************************************************************************
  *                                                                             *
  * The set of DEKs (data encryption keys) for at-rest encryption.              *
  * i.e. when encrypting/decrypting data for attributes with 'encrypt: true'.   *
  *                                                                             *
  * > The 'default' DEK is used for all new encryptions, but multiple DEKs      *
  * > can be configured to allow for key rotation.  In production, be sure to   *
  * > manage these keys like you would any other sensitive credential.          *
  *                                                                             *
  * > For more info, see:                                                       *
  * > https://sailsjs.com/docs/concepts/orm/model-settings#?dataEncryptionKeys  *
  *                                                                             *
  ******************************************************************************/

  dataEncryptionKeys: {
    default: 'blahblah'
  },


  /***************************************************************************
  *                                                                          *
  * Whether or not implicit records for associations should be cleaned up    *
  * automatically using the built-in polyfill.  This is especially useful    *
  * during development with sails-disk.                                      *
  *                                                                          *
  * Depending on which databases you're using, you may want to disable this  *
  * polyfill in your production environment.                                 *
  *                                                                          *
  * (For production configuration, see 'config/env/production.js'.)          *
  *                                                                          *
  ***************************************************************************/

  cascadeOnDestroy: true


};

Почтальон: remotehost: xxxx/user? ______________________

    {
    "id": 1,
    "createdAt": "2017-12-30T12:51:10Z",
    "updatedAt": "2017-12-30T12:51:10Z",
    "name": "Drake Bell",
    "roles": "DEFAULT_USER",
    "email": "[email protected]",
    "password": "Youll never know :D",
    "lastlogout": "2017-12-30T12:51:10Z"
}

Схема SQL

describe testauthdb.user;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| createdAt | bigint(20)   | YES  |     | NULL    |                |
| updatedAt | bigint(20)   | YES  |     | NULL    |                |
| name      | varchar(255) | YES  |     | NULL    |                |
| roles     | varchar(255) | YES  |     | NULL    |                |
| email     | varchar(255) | YES  | UNI | NULL    |                |
| password  | varchar(255) | YES  |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+



node_modules/парусов /Lib/Крючки/чертежи/действия /create.js

/**
 * Module dependencies
 */

var _ = require('@sailshq/lodash');
var async = require('async');
var formatUsageError = require('../formatUsageError');

/**
 * Create Record
 *
 * http://sailsjs.com/docs/reference/blueprint-api/create
 *
 * An API call to crete a single model instance using the specified attribute values.
 *
 */

module.exports = function createRecord (req, res) {

  var parseBlueprintOptions = req.options.parseBlueprintOptions || req._sails.config.blueprints.parseBlueprintOptions;

  // Set the blueprint action for parseBlueprintOptions.
  req.options.blueprintAction = 'create';

  var queryOptions = parseBlueprintOptions(req);
  var Model = req._sails.models[queryOptions.using];

  // Get the new record data.
  var data = queryOptions.newRecord;

  // Look for any many-to-one collections that are being set.
  // For example, User.create({pets: [1, 2, 3]}) where 'pets' is a collection of 'Pet'
  // via an 'owner' attribute that is 'model: 'user''.
  // We need to know about these so that, if any of the new children already had parents,
  // those parents get 'removedFrom' notifications.
  async.reduce(_.keys(Model.attributes), [], function(memo, attrName, nextAttrName) {

    var attrDef = Model.attributes[attrName];
    if (
      // Does this attribute represent a plural association.
      attrDef.collection &&
      // Is this attribute set with a non-empty array?
      _.isArray(data[attrName]) && data[attrName].length > 0 &&
      // Does this plural association have an inverse attribute on the related model?
      attrDef.via &&
      // Is that inverse attribute a singular association, making this a many-to-one relationship?
      req._sails.models[attrDef.collection].attributes[attrDef.via].model
    ) {
      // Create an 'in' query looking for all child records whose primary keys match
      // those in the array that the new parent association attribute (e.g. 'pets') is set to.
      var criteria = {};
      criteria[req._sails.models[attrDef.collection].primaryKey] = data[attrName];
      req._sails.models[attrDef.collection].find(criteria).exec(function(err, newChildren) {
        if (err) {return nextAttrName(err);}
        // For each child, see if the inverse attribute already has a value, and if so,
        // push a new 'removedFrom' notification onto the list of those to send.
        _.each(newChildren, function(child) {
          if (child[attrDef.via]) {
            memo.push({
              id: child[attrDef.via],
              removedId: child[req._sails.models[attrDef.collection].primaryKey],
              attribute: attrName
            });
          }
        });
        return nextAttrName(undefined, memo);
      });
    }

    else {
      return nextAttrName(undefined, memo);
    }

  }, function (err, removedFromNotificationsToSend) {

    if (err) {return res.serverError(err);}


    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // FUTURE: Use a database transaction here, if supported by the datastore.
    // e.g.
    // '''
    // Model.getDatastore().transaction(function during(db, proceed){ ... })
    // .exec(function afterwards(err, result){}));
    // '''
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    // Create new instance of model using data from params
    Model.create(data).meta(queryOptions.meta).exec(function created (err, newInstance) {

      // Differentiate between waterline-originated validation errors
      // and serious underlying issues. Respond with badRequest if a
      // validation error is encountered, w/ validation info, or if a
      // uniqueness constraint is violated.
      if (err) {
        switch (err.name) {
          case 'AdapterError':
            switch (err.code) {
              case 'E_UNIQUE': return res.badRequest(err);
              default: return res.serverError(err);
            }//•
          case 'UsageError': return res.badRequest(formatUsageError(err, req));
          default: return res.serverError(err);
        }
      }//-•

      // If we didn't fetch the new instance, just return 'OK'.
      if (!newInstance) {
        return res.ok();
      }

      // Look up and populate the new record (according to 'populate' options in request / config)
      Model
      .findOne(newInstance[Model.primaryKey], queryOptions.populates)
      .exec(function foundAgain(err, populatedRecord) {
        if (err) { return res.serverError(err); }
        if (!populatedRecord) { return res.serverError('Could not find record after creating!'); }

        // If we have the pubsub hook, use the model class publish method
        // to notify all subscribers about the created item
        if (req._sails.hooks.pubsub) {
          if (req.isSocket) {
            Model.subscribe(req, [populatedRecord[Model.primaryKey]]);
            Model._introduce(populatedRecord);
          }
          Model._publishCreate(populatedRecord, !req.options.mirror && req);
          if (removedFromNotificationsToSend.length) {
            _.each(removedFromNotificationsToSend, function(notification) {
              Model._publishRemove(notification.id, notification.attribute, notification.removedId, !req.options.mirror && req, {noReverse: true});
            });
          }
        }//>-

        // Send response
        res.ok(populatedRecord);
      }); // </foundAgain>

    });

  });



};



ТРАССИРОВКИ СТЕКА

TypeError: Model.create(...). Meta не является функцией в /home/username/api/node_modules/sails/lib/hooks/blueprints/actions/create.js:89:24 в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:421:16 at/home/username/api/node_modules/sails/node_modules/async/dist/async.js:2494:9 at/home/имя пользователя /api/node_modules/sails/node_modules/async/dist/async.js:421:16 при пополнении (/home/username/api/node_modules/sails/node_modules/async/dist/async.js:941:25) в iterateeCallback (/home/username/api/node_modules/sails/node_modules/async/dist/async.js: 931:17) в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:906:16 at/home/username/api/node_modules/sails/node_modules/async/dist/async.js:2491:13 в /home/username/api/node_modules/sails/lib/hooks/blueprints/actions/create.js:71:14 в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:2489:9 при пополнении (/home/username/api/node_modules/sails/node_modules/async/dist/async.js: 946: 17) в iterateeCallback (/home/username/api/node_modules/sails/node_modules/async/dist/async.js:931:17) в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:906: 16 в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:2491:13 в /home/username/api/node_modules/sails/lib/hooks/blueprints/actions/create.js: 71:14 в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:2489:9 при пополнении (/home/username/api/node_modules/sails/node_modules/async/dist/async.js: 946: 17) at iterateeCallback (/home/username/api/node_modules/sails/node_modules/async/dist/async.js:931:17) в /home/имя пользователя /api/node_modules/sails/node_modules/async/dist/async.js:906:16 в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:2491:13 в /home/имя пользователя /api/node_modules/паруса /lib/hooks/blueprints/actions/create.js:71:14 в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:2489:9 при пополнении (/home/username/api/node_modules/sail s/node_modules/async/dist/async.js: 946: 17) в iterateeCallback (/home/username/api/node_modules/sails/node_modules/async/dist/async.js:931:17) в /home/имя пользователя /api/node_modules/sails/node_modules/async/dist/async.js: 906: 16 at/home/username/api/node_modules/sails/node_modules/async/dist/async.js:2491:13 at/home/имя пользователя /api/node_modules/sails/lib/hooks/blueprints/actions/create.js: 71:14 at/home/username/api/node_modules/sails/node_modules/async/dist/async.js:2489:9 при пополнении (/home/username/api/node_modules/sails/node_modules/async/dist/async.js: 946: 17) в iterateeCallback (/home/username/api/node_modules/sails/node_modules/async/dist/async.js:931:17) в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:906:16 в /home/username/api/node_modules/sails/node_modules/async/dist/async.js:2491:13 в /home/username/api/node_modules/sails/lib/hooks/blueprints/actions/create.js:71:14 в /home/username/api/node_modules/sails/node_modules/async/dist/async.js: 2489: 9

Теги:
nginx
sails.js
postman

1 ответ

0

Извините за неудобства, моя проблема связана с routing.js. Я не попал в правый конечный пункт, и поэтому это довольно сложно определить ошибку. Может закончиться публикация этого сообщения на паруса forumn для очистки журнала ошибок.

Этот билет может быть закрыт (недостаточно очков)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню