I have created a Sails.js Model by using command "sails generate model". The model is generated as follows:
module.exports = {
connection: 'someMysqlServer',
attributes: {
amount : { type: 'float' },
country : { type: 'string' },
month : { type: 'string' }
}
};
I am trying to use .create() function of an instance of this model , inside a controller as follow , but I receive error :
var myModel = require ('../models/Info') ;
module.exports = {
getInfo: function (req, res) {
console.log("inside getInfo controller");
myModel.create({amount:3.5 , country:'spain' , month: 'january' }) ;
} ,
}
I receive the following error while using .create() function :
error: Sending 500 ("Server Error") response:
TypeError: Object #<Object> has no method 'create'
at module.exports.getInfo (/vagrant_data/inputinterface/b2bInputInterface/api/controllers/InputPageController.js:38:26)
at routeTargetFnWrapper (/usr/lib/node_modules/sails/lib/router/bind.js:178:5)
at callbacks (/usr/lib/node_modules/sails/node_modules/express/lib/router/index.js:164:37)
at param (/usr/lib/node_modules/sails/node_modules/express/lib/router/index.js:138:11)
at param (/usr/lib/node_modules/sails/node_modules/express/lib/router/index.js:135:11)
at pass (/usr/lib/node_modules/sails/node_modules/express/lib/router/index.js:145:5)
at nextRoute (/usr/lib/node_modules/sails/node_modules/express/lib/router/index.js:100:7)
at callbacks (/usr/lib/node_modules/sails/node_modules/express/lib/router/index.js:167:11)
at /usr/lib/node_modules/sails/lib/router/bind.js:186:7
at alwaysAllow (/usr/lib/node_modules/sails/lib/hooks/policies/index.js:209:11) [TypeError: Object #<Object> has no method 'create']
According to the following http://sailsjs.org/#/documentation/reference/waterline/models/create.html
this method should be accessible automatically ?
Models are globalized for you by Sails; there is no need to attempt to require() them on your own nor will this work as intended.
If your model file lives in api/models/Info.js, then your controller would look something like:
module.exports = {
getInfo: function (req, res) {
Info.create({amount:3.5 , country:'spain' , month: 'january' });
}
}
Rather than trying to follow the Waterline docs when creating a Sails app, you'll have a lot more luck following the Sails docs for models.
Related
Sails.js application fails to create one-to-many relationship in mongo db:
According to official Documentation I created two linked one-to-many entities, Post-Likes. I located them in api/models folder and defined as follows:
Like.js
module.exports = {
attributes: {
post: {
model: 'post',
required: true
}
}
Post.js
module.exports = {
attributes: {
likes: {
collection: 'like',
via: 'post'
},
user: {
model: 'user'
}
}
}
And I populate likes for the post with a following statement on the page:
const posts = await Post.find({user: id})
.sort('createdAt DESC')
.populate('user')
.populate('likes');
After I run sails.js app with command sails lift --drop and load the page with code above I receive the following error message in console:
error: Sending 500 ("Server Error") response: UsageError: Invalid
populate(s). Details: Could not populate like. There is no
attribute named like defined in this model.
at Object.module.exports [as user/profile] (/Users/new/Developer/ios/social/web_social/api/controllers/user/profile.js:8:30)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
I checked mongo db instance and I cannot see any empty or null like attribute for post entity:
try to make your model name initCap. like below
module.exports = {
attributes: {
post: {
model: 'Post',
required: true
}
}
I'm testing a mongoose model's validation, while trying to mock a validator, the model still has the reference to the original function, so the validation keeps calling the original function.
I want to test that the validator function get's called, however since the validator goes to the db I need to mock it.
This is my model:
const { hasRequiredCustoms } = require('../utils/validators')
const ProductSchema = new Schema({
customs: {
type: [String],
validate: hasRequiredCustoms // <- This is the validator
}
})
const Product = mongoose.model('Product', ProductSchema)
module.exports = Product
The original validators:
module.exports = {
hasRequiredCustoms(val) {
console.log('Original')
// validation logic
return result
},
//etc...
}
This is the mock for validators:
const validators = jest.genMockFromModule('../validators')
function hasRequiredCustoms (val) {
console.log('Mock')
return true
}
validators.hasRequiredCustoms = hasRequiredCustoms
module.exports = validators
And the test:
test('Should be invalid if required customs missing: price', done => {
jest.mock('../../utils/validators')
function callback(err) {
if (!err) done()
}
const m = new Product( validProduct )
m.validate(callback)
})
Every time I run the tests the console logs the Original. Why is the reference still going back to the original module? seems like I'm missing some super essential concept of how require works or the way mongoose stores the validators references.
Thanks for the help.
am using sails-sqlserver as my adapter am just trying the create a new row in the database in one of the follwing models.
This is the first model :
// Roles.js
module.exports = {
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
name: {
type: 'string'
},
approval_level: {
model: 'approval_levels'
},
specified: {
type: 'boolean'
},
entity_operations: {
collection: 'entity_operations',
via: 'roles',
dominant: true
},
users: {
collection: 'system_users',
via: 'role'
}
},
createRole: function (name, approval_level, cb) {
values = {
name: name,
approval_level: approval_level
};
Roles.create(values).exec(cb);
},
getAll: function (cb) {
Roles.find().exec(cb);
}
};
This is the second model :
// Entity_Operations.js
module.exports = {
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
entity_name: {
type: 'string'
},
operation: {
model: 'operations'
},
roles: {
collection: 'roles',
via: 'entity_operations'
}
},
getAll: function (cb) {
Entity_operations.find().exec(cb);
}
};
These two models have a many to many relationship together what am trying to do is just this :
Entity_operations.create({
entity_name: 'example',
operation: 6
}).exec((err, entity: Entity_operations) => {
console.log(entity);
});
then this error comes out without explaining anything that could help me know from where this error is coming from :
/opt/nodejs/back-heaven/dev/node_modules/sails-sqlserver/lib/adapter.js:435
Object.keys(connections[connection].collections[collection].definition).forEach(function(key) {
^
TypeError: Cannot read property 'collections' of undefined
at Object.getPrimaryKey (/opt/nodejs/back-heaven/dev/node_modules/sails-sqlserver/lib/adapter.js:435:42)
at Object.create (/opt/nodejs/back-heaven/dev/node_modules/sails-sqlserver/lib/adapter.js:374:24)
at module.exports.create (/opt/nodejs/back-heaven/dev/node_modules/waterline/lib/waterline/adapter/dql.js:84:13)
at child.createValues (/opt/nodejs/back-heaven/dev/node_modules/waterline/lib/waterline/query/dql/create.js:220:16)
at /opt/nodejs/back-heaven/dev/node_modules/waterline/lib/waterline/query/dql/create.js:74:20
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:726:13
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:52:16
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:269:32
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:44:16
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:723:17
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:167:37
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:52:16
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:269:32
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:44:16
at child.<anonymous> (/opt/nodejs/back-heaven/dev/node_modules/waterline/lib/waterline/utils/schema.js:152:44)
at fn (/opt/nodejs/back-heaven/dev/node_modules/waterline/lib/waterline/utils/callbacksRunner.js:41:10)
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:181:20
at iterate (/opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:262:13)
at Object.async.forEachOfSeries.async.eachOfSeries (/opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:281:9)
at Object.async.forEachSeries.async.eachSeries (/opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:214:22)
at Object.runner.beforeCreate (/opt/nodejs/back-heaven/dev/node_modules/waterline/lib/waterline/utils/callbacksRunner.js:44:9)
at /opt/nodejs/back-heaven/dev/node_modules/waterline/lib/waterline/query/dql/create.js:180:17
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:718:13
at iterate (/opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:262:13)
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:274:29
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:44:16
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:723:17
at /opt/nodejs/back-heaven/dev/node_modules/async/lib/async.js:167:37
when i tried the same code in a controller it succeded am trying it in a seeder of my own implementation this seeder before it starts i make a sails object programmatically and call sails.load
like this :
let myApp = new Sails();
myApp.load({}, (err) => {
if (err) throw err;
// this execute the seeds in the database seeder class
let seeder = require(`../../api/seeders/${scope.args[0]}`);
seeder.handle(() => {
myApp.lower((err) => {
if (err) throw err;
console.log(`Seeder ` + scope.args[0] + ` finished seeding`);
});
});
});
I also tried with sails.lift() and still the same error.
I have Found out the problem i was just making a callback function that should call sails.lower() which unload or close the sails I was putting it in the wrong place where it was called even before the model creation code starts.just forget to call it in the database callback function.
so , for anyone else who is facing this same problem in sails your problem is that sails actually not loaded or maybe when the operation you were working on started sails was working but, after that for some reason sails stopped which made the models do this weird looking problem I hope sails handle such errors in their code to show out a more expressive error messages.
I hope this helps anyone.
I am new to both Node.js and the Sails.js framework. I am trying to build a website/application with the framework, but am having trouble getting the model part to work as expected. I have looked at the documentation quite a bit, but still am not able to perform this basic task. I am using the PostgreSQL adapter.
The stack is as follows:
TypeError: Fragrance.create is not a function\n at Object.module.exports.index (/home/kelly/workspace/Hawthorne-Acres/api/controllers/HomeController.js:16:19)\n at wrapper (/usr/local/lib/node_modules/sails/node_modules/#sailshq/lodash/lib/index.js:3250:19)\n at routeTargetFnWrapper (/usr/local/lib/node_modules/sails/lib/router/bind.js:181:5)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:164:37)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:138:11)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:135:11)\n at pass (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:145:5)\n at nextRoute (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:100:7)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:167:11)\n at alwaysAllow (/usr/local/lib/node_modules/sails/lib/hooks/policies/index.js:224:11)\n at routeTargetFnWrapper (/usr/local/lib/node_modules/sails/lib/router/bind.js:181:5)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:164:37)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:138:11)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:135:11)\n at pass (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:145:5)\n at nextRoute (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:100:7)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:167:11)\n at module.exports (/usr/local/lib/node_modules/sails/lib/hooks/cors/clear-headers.js:14:3)\n at routeTargetFnWrapper (/usr/local/lib/node_modules/sails/lib/router/bind.js:181:5)\n at callbacks (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:164:37)\n at param (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:138:11)\n at pass (/usr/local/lib/node_modules/sails/node_modules/#sailshq/express/lib/router/index.js:145:5)"
Fragrance.js (located in the api/models folder):
module.exports = {
attributes: {
fragranceName: {
type: 'string',
required: true
},
listings: {
collection: "listing",
via: "fragrance"
}
}
};
The controller that calls the function
/**
* HomeController
*
* #description :: Server-side logic for managing Homes
* #help :: See http://sailsjs.org/#!/documentation/concepts/Controllers
*/
var Fragrance = require("../models/Fragrance");
module.exports = {
/**
* `HomeController.Index()`
*/
index: function(req, res) {
Fragrance.create({ fragranceName: 'Vanilla' }).exec(function(err, rec) {
console.log(rec.id);
});
return res.render("index", { title: "Welcome" });
},
/**
* `HomeController.About()`
*/
about: function(req, res) {
console.log("About place");
return res.render("about", { title: "About" });
},
/**
* `HomeController.Contact()`
*/
contact: function(req, res) {
return res.render("contact", { title: "Contact" });
}
};
It is probably something obvious, but I have made an effort to figure it out on my own, just without success. As such, any help would be appreciated.
Thanks.
The models in model folder are globally available. You can disable the functionality in config/globals.js. So you can drop
var Fragrance = require("../models/Fragrance");
Then you can create a record via:
Fragrance.create method
or
sails.models.fragrance.create method (Notice the model name is in lowercase.)
Personally, I prefer the second pattern and turning off the availability of models globally.
I am using mean.io to make sports event management system.I am trying to update a model Player with rest api and it throws this error from mongoose:
{ _id: 5411c79895d600440c698fa1,
email: 'abc#bcd.com',
name: 'James Bond',
username: 'james.bond',
games: [ 5411bd54786cfe2420f1e27a ],
teams: [],
roles: [ 'authenticated' ] }
[TypeError: Cannot read property '_id' of undefined]
PUT /api/players/5411c79895d600440c698fa1 500 199.402 ms - 36
I also tried to delete the _id proterty from player but it doesnot works either.
the method i have used to update the model player is :
exports.update = function(req, res) {
var player = req.player;
player = _.extend(player, req.body);
console.log(player);
Player.findOneAndUpdate(req.params.playerId, player,{new:true}, function (err, updatedPlayer) {
console.log(err);
if (err) {
return res.status(500).json({
error: 'Cannot update the player'
});
}
res.json(updatedPlayer);
});
And also if i used the model.save method provided in the default package article of mean.io, it shows another error. I have extended the user model in player package app.js file. So whenever I try to update one field, the field that I have declared in app.js are required and the path required error from mongoose is thrown.
You have two issues in your update request.
First, the findOneAndUpdate expects a dict as the query and not just the id, so you should give it {_id: req.params.playerId} instead.
Second, passing a mongoose object as the update data is risky, instead you should convert it to a dict like this var _player = player.toObject() and then have _player be passed to the update request. Remember that you need to remove the _id param of_player because you can't change the _id of a document. Before doing the update just do delete _player._id and you should be fine. Also, new is set to true by default so you won't need the options dict.
Here is your working code:
var player = _.extend(req.player, req.body);
var _player = player.toObject();
delete _player._id;
var query = {_id: req.params.playerId};
Player.findOneAndUpdate(query, _player, function (err, updatedPlayer) {
...
});
But in this case you shouldn't even have to do the first operation. Since you just want to update the data of req.body you can do:
var query = {_id: req.params.playerId};
var data = {
$set: req.body,
};
Player.findOneAndUpdate(query, data, function (err, updatedPlayer) {
...
});
This will update all the fields of the player matching the query with the values from req.body.