In my model I have a many-to-many-through association between User, Program through ProgramStaff:
User.js:
module.exports = {
attributes: {
username: {
type: 'string',
required: true,
unique: true
},
programs: {
collection: 'Program',
via: 'program',
through: 'programstaff'
}
}
}
Program.js:
module.exports = {
attributes: {
name: {
type: 'string'
},
personnel:{
collection : 'User',
via: 'user',
through: 'programstaff'
}
}
}
ProgramStaff.js:
module.exports = {
attributes: {
program: {
model: 'Program'
},
user: {
model: 'User'
},
permissions: {
type: 'integer'
}
},
tableName: 'program_staff'
};
(I need to program-staff through table to hold some sort of permissions and a user-program based, otherwise, I'd just use a regular many-to-many association).
My question is - can I create a new User' and associate with (existing)Program` using the rest or shortcuts routes?
I've tried to send
user.programs = [programId]; // doesn't do anything (or error)
//or
user.programs = [{program: progamId}]; // creates new program even though I send valid id of existing program
//or
user.programs = [{program: { id: progamId}}]; // error
But neither seem to create the ProgramStaff record.
P.S. I know I can do it with a User.create and a nested ProgramStaff.create calls within a route, or a Create and then Update rest/shortcut calls but I was wondering about a "automatic" way to do that.
Related
I am using Sails v1.1 -
Following the example from the "Through" associations on sails - https://sailsjs.com/documentation/concepts/models-and-orm/associations/through-associations
They defined a "through" association as basically a custom model. So this really isn't "through", it's just controlling the join table for the many to many relation.
So in the intermediate model, I added a custom attribute of isTyping seen below.
Is it possible to add to collection and set this intermediate value at same time?
For exmaple pseudocode with setIntermediate:
User.addToCollection(userId, 'pets', petId).setIntermediate('isTyping', true);
So following the example on the docs:
myApp/api/models/User.js
module.exports = {
attributes: {
name: {
type: 'string'
},
pets:{
collection: 'pet',
via: 'owner',
through: 'petuser'
}
}
}
myApp/api/models/Pet.js
module.exports = {
attributes: {
name: {
type: 'string'
},
color: {
type: 'string'
},
owners:{
collection: 'user',
via: 'pet',
through: 'petuser'
}
}
}
myApp/api/models/PetUser.js
module.exports = {
attributes: {
owner: {
model:'user'
},
pet: {
model: 'pet'
},
// I ADDED THIS INTERMEDIATE COLUMN NAME in the join table
isTyping: {
type: 'boolean',
defaultsTo: false
}
}
}
I don't know if this is right, but the way to do this is instead of using Pet.addToCollection(petId, 'owners', userId)/User.addToCollection(userId, 'pets', petId) or Pet.removeFromCollection(petId, 'owners', userId)/User.removeFromCollection(userId, 'pets', petId), is to instead do:
PetUser.create({ owner: userId, pet: petId, isTyping: true }).populate('user').populate('pet')
I'm not sure if right, and this doesn't support the array argument that addToCollection/removeFromCollection does. And you also have to massage the data in order to get a list of owners/pets with the pivot attribute of isTyping.
I am using Sails.js version 1.0.2. I am trying to assign uuid as primary key throughout the application. I tried putting
id: { type: 'string', defaultsTo:uuid.v4() } in model.js but it's saying Primary keys must be unique therefore can't contain a default value.
_________________EDIT_______________
I tried this code in my domain
beforeCreate: function (modelObj, next) {
modelObj.id = uuidv4.v4();
next();
}
And edit my Model.js configuration is like :
attributes: {
createdAt: { type: 'number', autoCreatedAt: true, },
updatedAt: { type: 'number', autoUpdatedAt: true, },
id: { type: 'string',required:true},
}
beforeCreate method never executes and throw the error while creating the record like:
error: Sending 500 ("Server Error") response:
{ UsageError: Invalid new record.
Details:
Missing value for required attribute `id`. Expected a string, but
instead, got: undefined
Please let me know if I am doing anything wrong.
Thanks
You can do something like this instead of giving default value
beforeCreate: function (modelObj, next) {
modelObj.id = uuid.v4();
next();
}
You can add this piece of function in your model. This gets invoked whenever there is a create operation on model.
Your Model.js should looks something like this
attributes: {
createdAt: { type: 'number', autoCreatedAt: true, },
updatedAt: { type: 'number', autoUpdatedAt: true, },
id: { type: 'string',required:true},
},
beforeCreate: function (modelObj, next) {
modelObj.id = uuid.v4();
next();
}
Sample code of my Controller and Model,
TestController.js
module.exports = {
create: function(req, res) {
Test.create({"name": "arshad"})
.then(function(result){
res.send("done");
})
}
};
Test.js Model
module.exports = {
attributes: {
id: { type: 'string', required: true },
name: { type: 'string' }
},
beforeCreate: function(obj, next) {
obj.id = 'someId';
next();
}
};
This is how your model and controller will look like. This will add someId as defined in beforeCreate function to the object
In your case you are using uuid package. Check in debugging mode whether uuid reference is available in beforeCreate or not
I must be misunderstanding this bullet point from the save documentation:
If you have any associations on the model they will currently be populated when you call .save(). This could cause issues with memory so to prevent this, you can take advantage of an experimental feature: passing in an options argument with populate: false set. Example: .save({ populate: false }, function() {})
http://sailsjs.com/documentation/reference/waterline-orm/records/save
My code...
//Person.js
attributes: {
name: {
type: 'string'
},
pets: {
collection: 'pet',
via: 'owner'
},
}
//Pet.js
attributes: {
animal: {
type: 'string'
},
owner: {
model: 'person'
}
}
//PersonController.js
create: function(req, res) {
Person.create({
name: 'Bob'
}).populate('pets').exec(function(err, person) {
person.pets.add({animal: 'dog'})
person.save(function(err) {
console.log(person);
});
})
}
And my output is Bob with no pets.
I have these models:
// Material.js
module.exports = {
attributes: {
name: {
type: 'string',
required: true
},
source_info: {
type: 'string',
required: true
},
category: { model: 'category_mat' }
}
};
and:
// Category_Mat.js
module.exports = {
attributes: {
name: {
type: 'string',
required: true
},
material:{
collection: 'material',
via: 'category'
}
},
};
but when I run the app I get this error:
/usr/local/lib/node_modules/sails/node_modules/waterline/node_modules/waterline-schema/lib/waterline-schema/foreignKeys.js:82
throw new Error('Trying to access a collection ' + collection + ' that is
^
Error: Trying to access a collection category_mat that is not defined.
at ForeignKeys.findPrimaryKey (/usr/local/lib/node_modules/sails/node_modules/waterline/node_modules/waterline-schema/lib/waterline-schema/foreignKeys.js:82:11)
at ForeignKeys.replaceKeys (/usr/local/lib/node_modules/sails/node_modules/waterline/node_modules/waterline-schema/lib/waterline-schema/foreignKeys.js:53:27)
at new ForeignKeys (/usr/local/lib/node_modules/sails/node_modules/waterline/node_modules/waterline-schema/lib/waterline-schema/foreignKeys.js:30:10)
at new module.exports (/usr/local/lib/node_modules/sails/node_modules/waterline/node_modules/waterline-schema/lib/waterline-schema.js:30:17)
at Waterline.initialize (/usr/local/lib/node_modules/sails/node_modules/waterline/lib/waterline.js:106:17)
at buildORM (/usr/local/lib/node_modules/sails/lib/hooks/orm/build-orm.js:48:15)
at Array.async.auto.instantiatedCollections [as 1] (/usr/local/lib/node_modules/sails/lib/hooks/orm/index.js:191:11)
at listener (/usr/local/lib/node_modules/sails/node_modules/async/lib/async.js:465:46)
at /usr/local/lib/node_modules/sails/node_modules/async/lib/async.js:419:17
at Array.forEach (native)
I used this documentation as reference:
http://sailsjs.org/#/documentation/concepts/ORM/Associations/OnetoMany.html
so I don't know what I'm missing or if there is a configuration that I have to do... any help?
Maybe it is because "category-mat" used on Material.js is not defined anywhere... try
// Category_Mat.js
module.exports = {
identity: 'category_mat',
attributes: {
name: {
type: 'string',
required: true
},
material:{
collection: 'material',
via: 'category'
}
},
};
If this works the only side effect is that even if you have config/globals.js/models set to "true", you won't be able to access the model in the controllers by using "Category_Mat". You will either have to use "sails.models.category_mat" or just "category_mat".
I'm using Sails#0.10rc-7 and I'm struggling to add something to a many-to-many record.
I have multiple users and multiple groups like this:
// Group.js
module.exports = {
attributes: {
description: {
type: 'string'
},
users: {
collection: 'user',
via: 'groups'
}
}
};
//User.js
module.exports = {
attributes: {
token: {
type: 'string'
},
groups: {
collection: 'group',
via: 'users'
}
}
};
I have an existing group record and an existing user record. I want to connect the user to the group.
I can succesfully do a PUT request like this:
PUT http://127.0.0.1:1337/api/user/1
{
"groups":1
}
This also works:
PUT http://127.0.0.1:1337/api/user/1
{
"groups": [1,2]
}
But what if I don't know the existing groups?