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
insails/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
toDS.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
insails/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
- Override the default
find
blueprint to handle nested associations. (See this SO answer)
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.