Sails Waterline Model attributes Validation type 'integer', 'float' fails - sails.js

My Model Attributes
per: {
type: 'float',
required: true
},
typeid: {
type: 'integer',
required: true
},
My input
{
per: '5GH',
typeid: '6SD',
}
I expect this should fail and will get error message something like
typeid:
[ { rule: 'integer',
message: 'undefined should be a integer
But on validation the o/p after validation
{
per: 5,
typeid: 6,
}
Do we need to manually validate integer and float in this case?

Official Sails Doc for Validation
As in documentation you can see that integer validation check for integer as well as string for validation.
According to what i have experienced with validation
For strictly validate use int,decimal in place of integer,float
problem with your scene is as follow.
a=5 =>integer in a
a="5" =>string but the integer value is 5
a="5a4" =>string but integer value is 5 not 54
a="a5" =>string and no integer value.Only this case will fail on validation rule
If you want strictly validate the attributes according to you custom rule then you can add custom validation rule in your models.See the code below:
module.exports = {
attributes: {
name: {
type:'string'
},
mail: {
type:'string',
defaultsTo:'a'
},
age:{
type:'string',
isInt:true
}
},
types:{
isInt:function(value){
console.log(value);
if(typeof value==='number' && value=== Math.floor(value)){
console.log('value is a number');
return true;
}
if(!isNaN(1*value)){
console.log(value);
return true;
}
return false;
}
}
};
So for each model you need to write custom validator.
And
i guess there is now way currently to write global custom validation
rule so that you could apply your validation on attributes of different models by writing validation
globally.

Related

MongoDB field only accepts 3 special values

slider_value: {
type: Number,
required: false,
},
This is the Mongoose schema for one of the fields in my MongoDB model.
It may only accept the integer values of 1, 4, and 10.
How can this validator be specified in the schema?
If you only need to store either one of these three values, storing them as a string, and validating using the enum key would be reasonable. For example that could look like this:
{
slider_value: {
type: String,
enum: ["1", "4", "10"],
},
}
Alternatively, if it is a requirement to store them in form of an int, you could use a custom validator to check a value before it's saved. That would look like this:
{
slider_value: {
type: Number,
validate: {
validator: value => value === 1 || value === 4 || value === 10,
message: props => `${props.value} is invalid for slider_value`,
},
},
}
For more details on custom validators and validation in mongoose in generell, here are the mongoose validation docs.

Sails js should not return password and email

I am trying to create CRUD app in sails js, and i am able to post data to my DB what i noticed is when i insert data on success sails return whole object. But if we don't want certain fields in response then how can we restrict it. Please help thanks.
module.exports = {
attributes : {
username : {
type: 'string',
required: true
},
password : {
type: 'string',
required: true
},
email : {
type: 'string',
required: true,
unique: true
}
},
toJson: function() {
var obj = this.toObject();
delete obj.password;
return obj;
},
beforeCreate: function(attribute, callback) {
console.log(attribute.password);
require('bcrypt').hash(attribute.password, 10, function(err, encryptedPassword) {
sails.log(err);
attribute.password = encryptedPassword;
sails.log(encryptedPassword);
callback();
});
}
};
#arbuthnott is partly correct above -- you do need toJSON rather than toJson -- but more importantly, the function needs to go inside the attributes dictionary, since it is an instance method:
attributes : {
username : {
type: 'string',
required: true
},
password : {
type: 'string',
required: true
},
email : {
type: 'string',
required: true,
unique: true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
}
I think the responses through sails default REST api for models runs them through .toJSON before returning, so you are doing this the right way.
However, you may have a case issue, like you should define .toJSON with uppercase instead of .toJson. Try making that switch and see if it solves your problem.
UPDATE
Sounds like this is not solving your issue. The sails docs from here say:
The real power of toJSON relies on the fact every model instance sent out via res.json is first passed through toJSON. Instead of writing custom code for every controller action that uses a particular model (including the "out of the box" blueprints), you can manipulate outgoing records by simply overriding the default toJSON function in your model. You would use this to keep private data like email addresses and passwords from being sent back to every client.
That sounds pretty explicitly like what we are trying to do, so maybe this is a sails bug. Perhaps it applies to find, but not create. Is that password returned when simply finding an existing user?
If you must, a sure way around this would be to override the default create action in your UserController:
create: function(req, res) {
User.create(req.body).exec(function(err, user) {
if (err) {
return res.json(err);
}
// explicitly call your own toJSON() to be sure
return res.send(user.toJSON());
});
},
This isn't ideal, especially if you have many model properties you want to hide in many api calls. But it will get the job done.
password: { type: 'string', required: true, protected: true }
protected:true is now deprecated on sails v1.0
You can use instead of that customToJSON
customToJSON: function() {
// Return a shallow copy of this record with the password and ssn removed.
return _.omit(this, ['password', 'ssn'])
}
password: { type: 'string', required: true, protected: true }
You can do this also.

Sailsjs beforeCreate not adding new value to values object

I am trying to set a value to the values object, but sails ignores it.
attributes: {
title: {
type: 'string',
required: true
},
testAttr: {
type: 'integer'
}
}
beforeCreate: function (values, cb) {
values.testAttr = 1;
cb();
},
My values object does NOT contain a testAttr value when it enters the beforeCreate method as this value is not sent via the request.
It could seem like it wont add/update this unless it is present on the values object to begin with.
What is the correct way to do this?
I think you have it almost right. The callback cb expects two arguments: an error, and a values hash. You just need to pass on your values:
beforeCreate: function (values, cb) {
values.testAttr = 1;
cb(null, values);
},

How can I validate a model attribute against another model attribute in Sails?

Let's say I have an Invoice model in SailsJS. It has 2 date attributes: issuedAt and dueAt. How can I create a custom validation rule that check that the due date is equal or greater than the issued date?
I tried creating a custom rule, but it seems I cannot access other properties inside a rule.
module.exports = {
schema: true,
types: {
duedate: function(dueAt) {
return dueAt >= this.issuedAt // Doesn't work, "this" refers to the function, not the model instance
}
},
attributes: {
issuedAt: {
type: 'date'
},
dueAt: {
type: 'date',
duedate: true
}
}
};
I hope you found a solution now, but for those interested to a good way to handle this i will explain my way to do it.
Unfortunatly as you said you can't access others record attributes in attribute customs validation function.
#Paweł Wszoła give you the right direction and here is a complete solution working for Sails#1.0.2 :
// Get buildUsageError to construct waterline usage error
const buildUsageError = require('waterline/lib/waterline/utils/query/private/build-usage-error');
module.exports = {
schema: true,
attributes: {
issuedAt: {
type: 'ref',
columnType: 'timestamp'
},
dueAt: {
type: 'ref',
columnType: 'timestamp'
}
},
beforeCreate: (record, next) => {
// This function is called before record creation so if callback method "next" is called with an attribute the creation will be canceled and the error will be returned
if(record.dueAt >= record.issuedAt){
return next(buildUsageError('E_INVALID_NEW_RECORD', 'issuedAt date must be equal or greater than dueAt date', 'invoice'))
}
next();
}
};
beforeCreate method in model as first param takes values. The best place for this kind of validation I see here.
beforeCreate: (values, next){
if (values.dueAt >= values.issuedAt) {
return next({error: ['...']})
}
next()
}

Validating Mongoose Mixed schema type

I have a schema:
// Schema
var Product = new Schema({
data: {
type: mongoose.Schema.Types.Mixed
},
created: {
type: Date,
'default' : Date.now
}
});
The 'data' field is used to store a json string which will vary. I do however want to perform some basic validation such as length etc.. However doing this:
// Validation
Product.path('data').validate(function (value) {
console.log(value);
return value.length > 0;
}, 'Data cannot be blank');
Throws an error about data not existing:
TypeError: Cannot read property 'length' of undefined
What is the best way to do this?
You are treating "value" as an object without checking if it really is. Try with this:
if(typeof value !== "undefined" && value !== null)
{
return value.length > 0
}