0

For experts familiar with sails.js: I have a Customers Model and to keep it simple lets say

/**
 * Customers.js
 */

module.exports = {

    attributes: {

        firstName: { type: 'string' },
        lastName: { type: 'string' }
    }
};

IMPORTANT: There is also a CustomerHistory Model as shown below. Whenever a Customer is created or updated, a corresponding CustomerHistory record should also be inserted/created.

     /**
     * CustomerHistory.js
     */

    module.exports = {

        attributes: {

            customer: { model: 'customer' },
            firstName: { type: 'string' },
            lastName: { type: 'string' },
            modifiedAt: { type: 'datetime'}
        }
    };

OPTIONS within Sails.js:

  1. Override or Create new Sails Blueprint actions (let's call it CreateWithHistory and UpdateWithHistory) which always inserts into CustomerHistory upon successful save into Customer. If this is the proposed solution, a code sample would help.

  2. Create custom controller actions (let's call it CreateWithHistory and UpdateWithHistory) which always inserts into CustomerHistory upon successful save into Customer. If this is the proposed solution, a code sample would help as to how to chain 2 Model.create and Model.update with Model.create actions.

  3. Create a custom Customers Model action to implicitly save into history on create or update. How to do this?

  • I would personally prefer third method where the trigger will be in Customer `afterCreate`/`afterUpdate` hooks. In 1st and 2nd both methods, there is chance that some other developer might use the default `.create` or `.update` method and then there won't be any corresponding action in `CustomerHistory`. 3rd case handles this situation. – khushalbokadey Jan 10 '18 at 10:56

1 Answers1

1

Sails js provides lifecycle callbacks for models you can use. They allow you to execute custom code whenever new models are created, updated, or at other times. I think you can accomplish what you want by adding callbacks to your Customer model. In Customer.js:

module.exports = {

    attributes: {
        firstName: { type: 'string' },
        lastName: { type: 'string' }
    },

    // this will create a new CustomerHistory for each Customer created
    afterCreate: function(customer, cb) {
        CustomerHistory.create({
            customer: customer.id,
            firstName: customer.firstName,
            lastName: customer.lastName,
            modifiedAt: new Date()
        }).exec(function(err, history) {
            if (err) { return cb(err); }
            cb();
        });
    },

    // update some fields in CustomerHistory after Customer is updated
    afterUpdate: function(customer, cb) {
        CustomerHistory.update({customer: customer.id}, {
            firstName: customer.firstName,
            lastName: customer.lastName,
            modifiedAt: new Date()
        }).exec(function(err, history) {
            if (err) { return cb(err); }
            cb();
        });
    }
};

This may not be the exact flow you want (for example, maybe you sometimes create the history first, sometimes don't modify the history on update, etc), but I think using the list of available callbacks should be able to accomplish what you want.

arbuthnott
  • 3,819
  • 2
  • 8
  • 21
  • This is the actual answer I found most optimal and implemented it. Thanks @arbuthnott – user3233791 Jan 13 '18 at 05:33
  • I try something like this but when it runs it says "Callback was already called" – Kevin Hernandez Aug 28 '19 at 01:20
  • 1
    @KevinHernandez this was posted for sails 0.12 - not sure if v1 behaves differenty. Your error sounds like `cb()` occurs twice in one of your lifecycle callbacks. In my answer above I avoid that by using an early return, like `return cb(err)`. Try following your logic and see if the callback can ever be invoked twice. – arbuthnott Aug 29 '19 at 11:41
  • @arbuthnott I figured it out, the function was async and I was getting weird race conditions because I was not using await. – Kevin Hernandez Aug 29 '19 at 13:48