0

Sails.js 0.10.4 returns inconsistent JSON results where nested associations exist. This causes all sorts of headaches with nested associations and Ember Data. What is the preferred way of getting the two to work together?

My stack is:

  • Sails.js 0.10.4
  • Ember CLI 0.0.42
  • Ember 1.7.0
  • Ember Data ~1.0.0-beta.7
  • ember-data-sails-adapter: ~2.0.0

I was hoping to use the sails-adapter so that I can convert to websockets at a later date. Should I just give up on this and use sails-ember-blueprints until Sails associations are a bit more mature?


Here is what I've tried, assuming three related models for instance user [hasMany]>> comment [belongsTo]>> commentType

Option 1

  • Set populate: true in sails/config/blueprints.js.
  • Use custom serializers in Ember which use the EmbeddedRecordsMixin

The serializer could look like:

// client/app/serializers/user.js
import DS from 'ember-data';
export default DS.JsonSerializer.extend(DS.EmbeddedRecordsMixin, {
    attrs: {
        comments: {
            embedded: 'always'
        }
    }
}

This works fine for one level of association, e.g. A --> B, however Sails does not currently populate nested embedded associations, so for A --> B --> C you will get a result like:

// query the sails API /api/v1/users/1
{
    id: 1,
    name: 'User1',
    comments: [{
        id: 1,
        name: 'Comment1',
        commentType: 1 // id instead of embedded record 
    }]
}

Option 1 Part 2

Setting the comment.commentType attribute to {async: true} in the Ember model does not work due to the inconsistent server responses. Accessing /api/v1/users/1 will get you the response above with just the commentType ID (which is fine with async), whilst accessing the comments directly will give you and embedded commentType record, e.g.

// query the sails API /api/v1/comments/1
{
    id: 1,
    name: 'Comment1',
    commentType: {
        id: 1,
        name: 'C'
    }
}

Ember does not like this :)

Option 2

  • Keep the associations as normal in Sails and change Ember's attributes from DS.belongsTo to DS.attr('number')
  • Ember can then use the setupController hook to perform a separate query to pull in the comment data

This kind of works for one-to-one relationships but doesn't play at all nicely for hasMany relationships.

Option 3

  • Set populate: false in sails/config/blueprints.js.
  • Set all Ember relationships to async:true

Sails appears to leave out the attributes completely if populate:false is set. Is this expected behaviour?

// query Sails API /api/v1/users/1
{
    id: 1,
    name: "A",
    // no mention of comments??
}

The following is therefore undefined and causes an Ember error:

myUser.get('comments');

Option 4

Seems a bit too much like reinventing Sails... The example given is for a single post, but this needs to handle populating multiple records. This rapidly enters async hell due to the lack of a model.Populate method in Sails.

Community
  • 1
  • 1
will-hart
  • 3,742
  • 2
  • 38
  • 48

1 Answers1

0

I had to abandon the ember adapter and use the Sails blueprints instead. By setting the Ember model async to false and performSideload to true on the Sails blueprints I can use the sideloaded data that sails sends with no issues.

will-hart
  • 3,742
  • 2
  • 38
  • 48
  • 1
    http://sanestack.com/ might be of interest for you as well. It does automatically implement the blueprints for you and set up the whole backend and frontend. – Markus Jan 11 '15 at 00:55