Loopback: <model>.verify is not a function\n

Created on 9 Mar 2016  路  11Comments  路  Source: strongloop/loopback

So, I read the documentation about manage the users. I also comes from this example: https://github.com/strongloop/loopback-example-user-management.

Then I try to make a model, called user-basic which bases on built-in model User.
Here's the user-basic.json:

{
  "name": "user-basic", 
  "base": "User",
  "idInjection": true, 
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [
    {
      "principalType": "ROLE",
      "principalId": "$everyone",
      "accessType": "READ",
      "permission": "ALLOW"
    }
  ],
  "methods": {}
}

Here's the user-basic.js

var config = require('../../server/config.json');
var path = require('path');


module.exports = function(UserBasic) {
          UserBasic.afterRemote('create', function(ctx, member, next) {
            console.log('> user.afterRemote triggered');
            var options = {
              type: 'email',
              to: UserBasic.email,
              from: '[email protected]',
              subject: 'Thanks for registering.',
              template: path.resolve(__dirname, '../../server/views/verify.ejs'),
              redirect: '/verified',
              user: UserBasic
            };
            UserBasic.verify(options, function(err) {
              console.log('aaaaa', member.location, err);
              if (err) {
                next(err);
              } else {
                next();
              }
            });

          });

          //send password reset link when requested
          UserBasic.on('resetPasswordRequest', function(info) {
            var url = 'http://' + config.host + ':' + config.port + '/reset-password';
            var html = 'Click <a href="' + url + '?access_token=' +
              info.accessToken.id + '">here</a> to reset your password';

            UserBasic.app.models.Email.send({
              to: info.email,
              from: info.email,
              subject: 'Password reset',
              html: html
            }, function(err) {
              if (err) return console.log('> error sending password reset email');
              console.log('> sending password reset email to:', info.email);
            });
          });
        };

In DataSource, I am using Cloudant (couchDB), here it is:

{
  "db": {
    "name": "db",
    "connector": "memory"
  }, 
  "cloudant-pop": {
    "host": "userxxx.cloudant.com",
    "port": 443,
    "url": "https://userxxx.com",
    "database": "population",
    "password": "userxxx",
    "name": "cloudant-pop",
    "connector": "couch",
    "db": "population",
    "protocol": "https",
    "auth": {
      "admin": {
       "username": "userxxx",
        "password": "userxxx"
      },
      "reader": {
        "username": "userxxx",
        "password": "userxxx"
      },
      "writer": {
        "username": "userxxx",
        "password": "userxxx"
      }
    },
    "user": "userxxx"
  }, 
  "emailDs": {
    "name": "emailDs",
    "connector": "mail",
    "transports": [
      {
        "type": "smtp",
        "host": "smtp.gmail.com",
        "secure": true,
        "port": 465,
        "tls": {
          "rejectUnauthorized": false
        },
        "auth": {
          "user": "[email protected]",
          "pass": "aaa"
        }
      }
    ]
  }
}

This is my model-config.json, Since I want to store the user credential to my Cloudant DB so I connect my user-basic model to my Cloudant Datasource:

"user-basic": {
    "dataSource": "cloudant-pop",
    "public": true,
    "options": {
      "emailVerificationRequired": true
    }
  }

I ran the server and try POST a new user via http://0.0.0.0:3008/explorer. It gives me an error:

{
  "error": {
    "name": "TypeError",
    "status": 500,
    "message": "UserBasic.verify is not a function",
    "stack": "TypeError: UserBasic.verify is not a function\n    at /Users/yogieputra/Desktop/backend_powercube/common/models/user-basic.js:23:23\n    at Function.<anonymous> (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback/lib/model.js:207:11)\n    at execStack (/Users/yogieputra/Desktop/backend_powercube/node_modules/strong-remoting/lib/remote-objects.js:480:26)\n    at RemoteObjects.execHooks (/Users/yogieputra/Desktop/backend_powercube/node_modules/strong-remoting/lib/remote-objects.js:492:10)\n    at phaseAfterInvoke (/Users/yogieputra/Desktop/backend_powercube/node_modules/strong-remoting/lib/remote-objects.js:652:10)\n    at runHandler (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-phase/lib/phase.js:130:5)\n    at iterate (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-phase/node_modules/async/lib/async.js:146:13)\n    at Object.async.eachSeries (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-phase/node_modules/async/lib/async.js:162:9)\n    at runHandlers (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-phase/lib/phase.js:139:13)\n    at iterate (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-phase/node_modules/async/lib/async.js:146:13)"
  }
}

When I check the Database, I got the user data that I've been POST recently.
Can you guys tell me what I've been missing?
Please help

Most helpful comment

All 11 comments

Hey @yogieputra8, check the API docs. The verify method is a prototype method, so you would need to call member.verify judging by your code.

For all your *myModel.js files, the argument passed into the module.exports function is a model class. So in your case, UserBasic is not a user/member, it is a user class. I think you have improperly used it in a couple places.

Let me know if that helps! If it doesn't solve your issue, I'll take another look.

Happy coding!

@richardpringle thank you for the response, I changed my /models/user-basic.js become this:

member.verify(options, function(err) {
              console.log('aaaaa', member.location, err);
              if (err) {
                next(err);
              } else {
                next();
              }
            });

And now it gives me another error when I try to POST data via explorer:

Web server listening at: http://0.0.0.0:3008
Browse your REST API at http://0.0.0.0:3008/explorer
> user.afterRemote triggered
events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: You must connect the Email Model to a Mail connector
    at Function.Email.send (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback/common/models/email.js:42:11)
    at sendEmail (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback/common/models/user.js:429:13)
    at /Users/yogieputra/Desktop/backend_powercube/node_modules/loopback/common/models/user.js:407:11
    at ModelConstructor.<anonymous> (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-datasource-juggler/lib/dao.js:2033:21)
    at ModelConstructor.next (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-datasource-juggler/lib/hooks.js:75:12)
    at ModelConstructor.<anonymous> (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-datasource-juggler/lib/dao.js:2032:28)
    at ModelConstructor.next (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-datasource-juggler/lib/hooks.js:75:12)
    at /Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-datasource-juggler/lib/dao.js:2031:28
    at doNotify (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-datasource-juggler/lib/observer.js:93:49)
    at doNotify (/Users/yogieputra/Desktop/backend_powercube/node_modules/loopback-datasource-juggler/lib/observer.js:93:49)

I already put the email connector in my datasources, why loopback warn me to connect the Email Model to a Mail connector?

In order to help you further, I'm going to ask you to fork the loopback-sandbox and then send me a link or if you have a public repo on github, I could also take a look at that. It looks to me as though you have setup the "mail" datasource correctly, but not attached it to the Email model in your model-config.json.

Ahh, I get it. I add the email connector to my model-config.json just like this:

  "Email": {
    "dataSource": "emailDs"
  },

And everythings working fine

@richardpringle thank you for the help. Really appreciate that :)

Glad it worked it worked out! Closing the issue now.

I think to prevent this issue from opening again we can clear up the documentation. The example here re-uses user as the model name and the model instance, and it's causing people a lot of confusion. Seen this issue raised more than a couple times. Switching the first instance of user with User would clear everything up.

@crandmck, want me to open a new issue for the above comment?
@enceladus is right, we shouldn't use the same variable name twice. I might also even suggest that the upper/lower-case 'u' might not be enough of a difference for new LoopBack users (developers). Maybe something like userInstance could be used to make things unquestionably clear.

I personally prefer the upper/lower-case convention for instance vs. class but I don't think it's the best for examples.

@richardpringle I'd appreciate it if you could update the docs, since you're up to speed on this specific thing, and I'm at an offsite currently.

@crandmck @enceladus, could you both take a look please? I made some changes so please point out anything that I may have missed.

Cheers

Just looked at the docs and it looks better to understand for new loopback users now. Thanks again @richardpringle

Was this page helpful?
0 / 5 - 0 ratings