Building model "user" to "user_flag" to "user" - node.js

I have two models:
User
'use strict';
var Mystical = require('../mystical'),
Blog = require('./blog'),
Flag = require('./user/flag');
module.exports = Mystical.db.Model.extend({
tableName: 'user',
defaults: {
isAdmin: 0,
isConfirmed: 0
},
blogs: function blogs() {
return this.hasMany(Blog, 'userId');
},
flags: function flags() {
return this.hasMany(Flag, 'userId');
}
});
...and Flag:
'use strict';
var Mystical = require('../../mystical'),
User = require('../../model/user');
module.exports = Mystical.db.Model.extend({
tableName: 'user_flag',
user: function user() {
return this.belongsTo(User, 'id');
}
});
On a page I try to get a flag:
(new Flag({ content: req.params.identifier, flag: 'register_complete' })).fetch({ withRelated: ['user'] }).then(onData).otherwise(function(error) {
console.log(error);
});
But every time I call this function the otherwise callback gets triggered:
TypeError: object is not a function
at exports.Relation.RelationBase.extend.relatedInstance (/my/secret/dir/node_modules/bookshelf/dialects/sql/relation.js:217:29)
at exports.Relation.RelationBase.extend.init (/my/secret/dir/node_modules/bookshelf/dialects/sql/relation.js:43:39)
at exports.Model.ModelBase.extend.belongsTo (/my/secret/dir/node_modules/bookshelf/dialects/sql/model.js:37:76)
at user (/my/secret/dir/core/model/user/flag.js:10:21)
at EagerBase.fetch (/my/secret/dir/node_modules/bookshelf/dialects/base/eager.js:56:40)
at /my/secret/dir/node_modules/bookshelf/dialects/sql/model.js:232:60
at NearFulfilledProxy.when (/my/secret/dir/node_modules/bookshelf/node_modules/when/when.js:465:43)
at Object._message (/my/secret/dir/node_modules/bookshelf/node_modules/when/when.js:389:25)
at deliver (/my/secret/dir/node_modules/bookshelf/node_modules/when/when.js:299:7)
at /my/secret/dir/node_modules/bookshelf/node_modules/when/when.js:296:63
For now I have tried to generate my association with hasMany, hasOne, belongsTo as well as belongsToMany. But nothing works...
Anyone an idea?

I have a feeling this might be a circular reference problem:
Try replacing:
return this.hasMany(Flag, 'userId');
with
return this.hasMany(require('./user/flag'), 'userId');
and
return this.belongsTo(User, 'id');
with
return this.belongsTo(require('../../model/user'), 'id');
and see if you still have the same issue.

Related

Sailsjs/Passport add fields to User

Sails noob here. I have sailsjs (v0.12.3) running with passport and everything is currently working. The User model is located in /node_modules/sails-auth/api/models/User.js and has username, email, and passports fields. I want to add additional fields (like bday ->string, favorite_car-> string) to the users table, but can't find a good way to do this. Editing the existing User.js file to add the new attributes would probably work, but seems like a bad idea. I've tried creating a User.js file (in myproj/api/models/) but i get an error stating:
Error: on mapping custom foreign keys: role->user. Attribute: roles does not exist on: collection: user
Any insight into the best way to do this would be greatly appreciated.
Thanks
added:
I've tried many different iterations from a empty User.js file (in myproj/api/models/) to the entire code that come with sails-auth (in myproj/node_modules/sails-auth/dist/api/models/User.js). They all produce the same error. Here is code that tried from the node_modules' User.js:
'use strict';
var _ = require('lodash');
var crypto = require('crypto');
/** #module User */
module.exports = {
attributes: {
username: {
type: 'string',
unique: true,
index: true,
notNull: true
},
email: {
type: 'email',
unique: true,
index: true
},
passports: {
collection: 'Passport',
via: 'user'
},
getGravatarUrl: function getGravatarUrl() {
var md5 = crypto.createHash('md5');
md5.update(this.email || '');
return 'https://gravatar.com/avatar/' + md5.digest('hex');
},
toJSON: function toJSON() {
var user = this.toObject();
delete user.password;
user.gravatarUrl = this.getGravatarUrl();
return user;
}
},
beforeCreate: function beforeCreate(user, next) {
if (_.isEmpty(user.username)) {
user.username = user.email;
}
next();
},
/**
* Register a new User with a passport
*/
register: function register(user) {
return new Promise(function (resolve, reject) {
sails.services.passport.protocols.local.createUser(user, function (error, created) {
if (error) return reject(error);
resolve(created);
});
});
}
};

sails js save many to many is only one way

i have two models:
user.js
module.exports = {
attributes: {
...
profile: {
model: 'Profile'
},
groups: {
collection: 'group',
via: 'users',
dominate: true
},
roles: {
collection: 'role',
via: 'users',
dominate: true
}
}};
and, group.js
module.exports = {
attributes: {
...
users: {
collection: 'user',
via: 'groups'
}
}};
when i try to add users to a group (when i select a group and add users to it), it works as it is supposed to,
var defer = q.defer();
baseDbContext.single(req, 'users')
.then(function(op){
if(!op.status || !op.obj) {
defer.resolve(notFound);
return;
}
op.obj.users = [];
_.each(req.users, function(item){
op.obj.users.add(item);
});
op.obj.save(function(err, obj){
if(err) defer.reject(operationResult().throwException(err));
else defer.resolve(operationResult().succeed());
});
});
return defer.promise;
but when i try to add groups to the user (when i select the user and add groups to it) it fails silently!!!
var defer = q.defer();
baseDbContext.single(req, 'groups')
.then(function(op){
if(!op.status || !op.obj) {
defer.resolve(notFound);
return;
}
op.obj.groups = [];
_.each(req.groups, function(item){
op.obj.groups.add(item);
});
op.obj.save(function(err, obj){
if(err) defer.reject(operationResult().throwException(err));
else defer.resolve(operationResult().succeed());
});
});
return defer.promise;
when i check it in sails console it shows :
throw new Error('Unknown rule: ' + ruleName);
Error: Unknown rule: dominate
this is a simple many to many insertion why would it fail?
(a note about code, the function baseDbContext.single finds a object based on its id and the second parameter is for populate)
Seems like you have a misprint, documentation says that the rule you need is writes as "dominant: true", not "dominate: true".

Fetching from Model has not supply the defaults

In my app, I am fetching the data from /home -by home Model. the Model contains the defaults object. But while i fetch the data, I am not able to see the default object in the model.
here is my model :
define(['backbone'], function(Backbone){
"use strict";
socialApp = window.socialApp || {};
socialApp.homeModel = Backbone.Model.extend({
url: "/home",
defaults:{
"category":"Level-1"
}
});
return socialApp.homeModel;
});
here is my view.js :
socialApp.homeView = Backbone.Marionette.ItemView.extend({
tagName:'div',
initialize:function () {
var that = this;
this.model.fetch().done(function(data){
that.render(data) // i am fetching here
});
},
render: function (data) {
console.log(data) //there is no defaults object here...
this.$el.html(homeTemp(data));
}
});
What is wrong here? I am using Nodejs as a server.
here is the console what i am getting:
{
__v: 0
_id: "5416ce23fc0c41ec0f03f672"
email: "afzil#gmail.com"
firstName: "Mohamed"
lastName: "Afzil"
password: "afzil"
username: "afzil"
}
thanks in adavnce.
As i can see in promise 'done' callback you have only fetch results, not model.
please modify your initialize function to this:
initialize: function () {
var that = this;
this.model.fetch({
success: function(model){
that.render(model.toJSON());
}
});
}

Virtual properties in SequelizeJS do not work

I have following schema in SequelizeJS:
var moment = require('moment');
module.exports = function(sequelize, DataTypes) {
var Account = sequelize.define('Account', {
suspended: {
type: DataTypes.BOOLEAN,
defaultValue: false
}
}, {
getterMethods: {
trialDaysLeft: function() {
return 5;
}
},
tableName: 'accounts'
});
return Account;
};
I want to get trialDaysLeft when I call account.trialDaysLeft property.
I am getting
TypeError: Property 'trialDaysLeft' of object [object Object] is not a function
Where am I wrong?
The name might not be the most intuitive but what getterMethods actually does is generate properties with getter methods on the instance objects.
So in this instance you would need to call instance.trialDaysLeft and not instance.trialDaysLeft() (which i'm guessing is what you're doing).

Compound JS Relationship Access

I have defined 2 schema objects as below (for use in a mongodb)
var User = describe('User', function () {
property('name', String);
property('email', String);
property('password', String);
set('restPath', pathTo.users);
});
var Message = describe('Message', function () {
property('userId', String, { index : true });
property('content', String);
property('timesent', Date, { default : Date });
property('channelid', String);
set('restPath', pathTo.messages);
});
Message.belongsTo(User, {as: 'author', foreignKey: 'userId'});
User.hasMany(Message, {as: 'messages', foreignKey: 'userId'});
But I am unable to access the related messages object:
action(function show() {
this.title = 'User show';
var that = this;
this.user.messages.build({content:"bob"}).save(function(){
that.user.messages(function(err,message){
console.log('Messages:');
console.log(message);
});
});
// ... snip ...
}
});
Despite a new message being added to the message collection the array of messages is always empty.
I ran db.Message.find({userId:'517240bedd994bef27000001'}) through the mongo shell and that displayed the messages as you would expect, so I am begining to wonder if there is an issue with the mongo adapter.
One to Many relationship in CompoundJS Shows a similar issue (I think).
As far as I can work out from the docs, this should work. What am I doing wrong?
EDIT:
After applying the changes to my schema as suggested by Anatoliy I dropped my mongo database and updated npm but then when I tried to create a new user I got the below:
Express
500 TypeError: Object #<Object> has no method 'trigger' in users controller during "create" action
at Object.AbstractClass._initProperties (/mnt/share/chatApp2/node_modules/jugglingdb/lib/model.js:123:10)
at Object.AbstractClass (/mnt/share/chatApp2/node_modules/jugglingdb/lib/model.js:31:10)
at Object.ModelConstructor (/mnt/share/chatApp2/node_modules/jugglingdb/lib/schema.js:193:23)
at Function.AbstractClass.create (/mnt/share/chatApp2/node_modules/jugglingdb/lib/model.js:222:15)
at Object.create (eval at (/mnt/share/chatApp2/node_modules/compound/node_modules/kontroller/lib/base.js:157:17), :16:10)....
EDIT2:
Create action:
action(function create() {
User.create(req.body.User, function (err, user) {
respondTo(function (format) {
format.json(function () {
if (err) {
send({code: 500, error: user && user.errors || err});
} else {
send({code: 200, data: user.toObject()});
}
});
format.html(function () {
if (err) {
flash('error', 'User can not be created');
render('new', {
user: user,
title: 'New user'
});
} else {
flash('info', 'User created');
redirect(path_to.users);
}
});
});
});
});
It's an issue with ObjectID. In your schema code:
property('userId', String, { index : true });
So userId is string, but when you call user.messages user.id used (and it's an ObjectID).
As a solution just remove this line from your schema definition.
P.S. in your case you can define relations as:
Message.belongsTo('author', {model: User, foreignKey: 'userId'});
User.hasMany('messages');

Resources