Reputation: 196
I have a "character" model with two columns which save JSON objects, which store arrays of "limb" model objects (as JSON objects). On a page the user selects which "limbs" belong in either of the two columns ("equipped" or "spare"), and that selection is sent to the server via a form.
I know that the form works, because the next page successfully displays all six of the "limb" objects which exist in JSON arrays. The exact same lists should get saved into the "character's" "spare" and "equipped" columns.
90% of the time it works perfectly. But occasionally it will happen that only four or five of the "limb" objects actually get stored in the "character" database, even though the exact same lists successfully displayed all six of the "limbs."
The process is that the form will send an array of ID numbers, and then the server will instantiate "limb" objects from the database based on those IDs. As I said, this part works flawlessly 100% of the time, because the page always shows all six "limb" objects. But occasionally the exact same lists will be missing one or two entries when stored in the "character's" columns in the database.
Here is the relevant code:
updateCharacter: function(req, res) {
if(req.session.user){
// FIRST get the form info and store it:
var equipped_limb_ids = req.param('char_equipped_limbs').split(",");
var spare_limb_ids = req.param('char_spare_limbs').split(",");
var new_name = req.param('new_char_name');
var char_id = req.param('char_id_out');
// Next get fresh limbs based on the limbs IDs:
var spare_limbs = { "limbs": [] };
var equipped_limbs = { "limbs": [] };
for(var i=0; i<spare_limb_ids.length; i++){
var limb_id = spare_limb_ids[i].replace(/\W/g, '');
Limb.findOne().where({ 'id': limb_id })
.exec(function(err, result){
if(result){
spare_limbs["limbs"].push(result);
}
});
}
for(var i=0; i<equipped_limb_ids.length; i++){
var limb_id = equipped_limb_ids[i].replace(/\W/g, '');
Limb.findOne().where({ 'id': limb_id })
.exec(function(err, result){
if(result){
equipped_limbs["limbs"].push(result);
}
});
}
// Prepare info to update the character, and send the same info to the front page
var updated_info = {
name: new_name,
equipped_limbs: equipped_limbs,
spare_limbs: spare_limbs
};
Character.update( { id:char_id }, updated_info )
.exec( function(err, char) {
return res.view('viewcharacter', {
name:new_name,
spares: spare_limbs,
equipped: equipped_limbs,
char_id: char_id
});
});
}else{
return res.view('login');
}
}
So you can see that the exact same list is being stored in the database which is also being sent to the 'viewcharacter' page, but 'viewcharacter' ALWAYS shows all of the "limbs" which were sent and created, but not all the created "limbs" are stored in the database when I update the "character" object.
Thanks in advance
Upvotes: 0
Views: 167
Reputation: 3819
Your code isn't running in the order you think it is... all of the callbacks that you put inside your .exec
blocks (including all your array push's) are going to execute at some point later - there is not guarantee about in what order, or how much later.
When the code usually works, it's because usually all your limb objects happen to be found before you update the Character
in the db, but the order is not guaranteed the way you have it written.
To understand what's happening, just insert some sails.log
calls, for example just before each Limb.findOne
, and also just before each push to your limb arrays. And then also before the Character.update
and the return res.view
.
The solution isn't totally easy - you need to wait for an uncertain number of async calls to complete. If you use a library like Q or Bluebird, they have ways to do that. Without adding any libraries, you can make this work by combining your queries for the "limbs" and being clever with the results:
Limb.find({id: equipped_limb_ids.concat(spare_limb_ids)}).exec(function(err, limbs) {
// handle the error...
// limbs is a list of all needed limbs in no particular order.
// create a dictionary to look up by id
var limbDict = {};
for (var i = 0; i < limbs.length; i++) { limbDict[limbs[i].id] = limbs[i]; }
// now create your limb object arrays
var equippedLimbs = [], spareLimbs = [];
// if you're comfortable with .map, you can use this, but here's the old fasioned way
for (var i = 0; i < equipped_limb_ids.length; i++) {
if (limbDict[equipped_limb_ids[i]]) {
equippedLimbs.push(limbDict[equipped_limb_ids[i]]);
}
}
for (var i = 0; i < spare_limb_ids.length; i++) {
if (limbDict[spare_limb_ids[i]]) {
spareLimbs.push(limbDict[spare_limb_ids[i]]);
}
}
// now you have all your "limbs"... update your character and return...
});
Upvotes: 1