5

Suppose I have this model:

module.exports = {

  attributes: {

    title: {
      type: 'string',
      required: true
    },

    content: {
      type: 'string',
      required: true
    },

    createdBy: {
      type: 'string',
      required: true
    }
  }
}

I need to set the current user id to the model's createdBy attribute. I thought I could do that with the beforeValidate lifecycle callback, but I can't access the request object where the current user is stored. Is there a way to access it, or should I solve this somehow else?

I tried this with no success:

beforeValidate: function (values, next) {
  var req = this.req; // this is undefined
  values.createdBy = req.user.id;
  next();
}
Martin Schaer
  • 3,986
  • 1
  • 23
  • 28

2 Answers2

10

Since requests are outside the scope of the ORM, I guessed my approach was wrong, and that I needed to add the createdBy data to the req.body within a middleware. But since that does not to be done for each request, I guessed it would be better to do that with a policy. Like this:

PostController: {

  '*': ['passport', 'sessionAuth'],

  create: ['passport', 'sessionAuth',
    function (req, res, next) {
      if (typeof req.body.createdBy === 'undefined') {
        req.body.createdBy = req.user.id;
      }
      next();
    }
  ]
}

This way I don't need to override the blueprint.

Martin Schaer
  • 3,986
  • 1
  • 23
  • 28
  • 1
    I'm surprised more people aren't recommending this. Always adding it in the controller is an anti-pattern to blueprint goals. Policies make this much easier. – Matt Lo Jul 17 '15 at 00:37
  • Ok, but how am I able to access req inside lifecycle callback thanks to this policy? – Adam Pietrasiak Jan 05 '16 at 08:15
  • @AdamPietrasiak this does not solve that, instead this "solution" recommends the use of a middleware to achieve what I originally was trying to do. See Matt Lo's comment. – Martin Schaer Mar 09 '16 at 02:09
1

You can do it in two ways.

First is to add that data in controller. Something like

// /api/controllers/mycontroller.js
module.exports = {
    new: function(req, res) {
        if (typeof req.user.id !== 'undefined') {
            req.body.createdBy = req.user.id;     // req.body or req.params
        }
        MyModel.create(req.body /* ... */)
    }
}

If you have a lot of data manipulation with MyModel it might be annoying. So you can add static method to your model to save it with user id. Something like:

// /api/models/myModel.js
module.exports = {
    attributes: {/* ... */},

    createFromRequest: function(req, cb) {
        // do anything you want with your request
        // for example add user id to req.body
        if (typeof req.user.id !== 'undefined') {
            req.body.createdBy = req.user.id;
        }
        MyModel.create(req.body, cb);
    }
}

And the use it in your controller

// /api/controllers/mycontroller.js
module.exports = {
    new: function(req, res) {
        MyModel.createFromRequest(req, function(err, data) {
            res.send(data);
        });
    }
}
Boris Zagoruiko
  • 12,705
  • 15
  • 47
  • 79
  • Thanks Glen! I was trying to avoid overriding the blueprint actions. But I don't know what if best. Look at my own answer, does that make sense? – Martin Schaer Feb 06 '15 at 18:02
  • 1
    @MartinSchaer, I would not use it for real project. The first reason, that is not obvious to use policies in such way. I mean that if I have project and know that somewhere user id added to request body before it saves, policies was the last place where I would try to find it. The second reason is that it is hard to reuse this code. If you want to add user id to other methods of model you should write this function again (or create single policy to add user id). This is my opinion, but I believe that policy should be used for access manipulation and models should be used for data manipulation. – Boris Zagoruiko Feb 09 '15 at 09:23