František Žiačik
František Žiačik

Reputation: 7612

Sails blueprint populate not working on creation?

According to this, when creating a new record with association to some other record, the response should contain the associated record populated.

POST /pony
{
  "name": "Pinkie Pie",
  "pet": 1
}

And the response should be like

{
  "name": "Pinkie Pie",
  "pet": {
    "name": "Gummy",
    "id": 1
  },
  "id": 4,
  "createdAt": "2013-10-18T01:22:56.000Z",
  "updatedAt": "2013-11-26T22:54:19.951Z"
}

Instead, I actually get a "pet": 1 in response.

My steps are like this:

  1. sails new test
  2. sails generate api pony
  3. sails generate api pet
  4. add "name" : "string" to both models
  5. add "pet" : { "model" : "pet" } to pony model

Should I do anything else to get the blueprint api populate the pet property in response of pony creation or do I have to do another request just to get the pet populated?

Upvotes: 4

Views: 792

Answers (2)

grocky
grocky

Reputation: 573

Andi's answer is spot on. Here's an implementation using waterline's promises

api/blueprints/create.js

'use strict';

let actionUtil = require('sails/lib/hooks/blueprints/actionUtil')

/**
 * Create Record
 *
 * post /:modelIdentity
 *
 * An API call to find and return a single model instance from the data adapter
 * using the specified criteria.  If an id was specified, just the instance with
 * that unique id will be returned.
 *
 * Optional:
 * @param {String} callback - default jsonp callback param (i.e. the name of the js function returned)
 * @param {*} * - other params will be used as `values` in the create
 */
module.exports = function createRecord (req, res) {
  var Model = actionUtil.parseModel(req);

  var data = actionUtil.parseValues(req);

  Model
    .create(_.omit(data, 'id'))
    .then(newInstance => Model.findOne(newInstance.id).populateAll())
    .then(res.created)
    .catch(res.negotiate);
}

Upvotes: 1

Andi N. Dirgantara
Andi N. Dirgantara

Reputation: 2051

By default, blueprint at create action is not doing populateAll trough any new instance that created. Look at it's source code.

If you want to auto populate created content, you should override default blueprint at create action, to something like.

create: function(req, res){
  var Model = actionUtil.parseModel(req);

  // Create data object (monolithic combination of all parameters)
  // Omit the blacklisted params (like JSONP callback param, etc.)
  var data = actionUtil.parseValues(req);


  // Create new instance of model using data from params
  Model.create(data).exec(function created (err, newInstance) {

    // Differentiate between waterline-originated validation errors
    // and serious underlying issues. Respond with badRequest if a
    // validation error is encountered, w/ validation info.
    if (err) return res.negotiate(err);

    // If we have the pubsub hook, use the model class's publish method
    // to notify all subscribers about the created item
    if (req._sails.hooks.pubsub) {
      if (req.isSocket) {
        Model.subscribe(req, newInstance);
        Model.introduce(newInstance);
      }
      Model.publishCreate(newInstance, !req.options.mirror && req);
    }

    // Send JSONP-friendly response if it's supported
    // populate it first
    Model
      .findOne({id:newInstance.id})
      .populateAll()
      .exec(function(err, populatedInstance){
        if (err) return res.negotiate(err);

        res.created(populatedInstance);
      });
  });
}

Upvotes: 4

Related Questions