belongsTo data of the model isn't loaded

Here is my model: loan.js

import DS from 'ember-data';
export default DS.Model.extend({
  notes: DS.attr('string', {defaultValue: ''}),
  returned: DS.attr('boolean'),
  createdAt: DS.attr('date'),
  friend: DS.belongsTo('friend'),
  article: DS.belongsTo('article')
});

This is my model for article:

import DS from 'ember-data';
import { hasMany } from 'ember-data/relationships';

export default DS.Model.extend({
  name: DS.attr('string'),
  loans: hasMany('loan')
});

For my route loans/index this is what I have

import Ember from 'ember';

export default Ember.Route.extend({
  model(){
    return this.modelFor('friends.show').get('loans');
  }
});

Finally my loans/index.hbs is as such

<tbody>
    {{#each model as |loan|}}
    <tr>
      <td>
        {{log loan}}
        {{loan.article.name}}
      </td>
      <td>
        {{loan.notes}}
      </td>
      <td>
        {{loan.createdAt}}
      </td>
    </tr>
    {{/each}}
  </tbody>

Finally the response from the API

{

    "data": [
        {
            "id": "1",
            "type": "loans",
            "links": {
                "self": "http://ember-cli-devinda.herokuapp.com/loans/1"
            },
            "attributes": {
                "notes": "fgfhf",
                "returned": false,
                "created-at": "2017-08-08T11:22:25.136Z"
            },
            "relationships": {
                "article": {
                    "links": {
                        "self": "http://ember-cli-devinda.herokuapp.com/loans/1/relationships/article",
                        "related": "http://ember-cli-devinda.herokuapp.com/loans/1/article"
                    }
                },
                "friend": {
                    "links": {
                        "self": "http://ember-cli-devinda.herokuapp.com/loans/1/relationships/friend",
                        "related": "http://ember-cli-devinda.herokuapp.com/loans/1/friend"
                    }
                }
            }
        }
    ],
    "links": {
        "first": "http://ember-cli-devinda.herokuapp.com/friends/1/loans?page%5Bnumber%5D=1&page%5Bsize%5D=10",
        "last": "http://ember-cli-devinda.herokuapp.com/friends/1/loans?page%5Bnumber%5D=1&page%5Bsize%5D=10"
    }

}

When i include {{loan.article.name}} the console only prints out ā€˜loanā€™ once. This is my result when I convert loan to json with .toJSON()

If i take the ā€˜loanā€™ object, save it in the console (as temp0) and run temp0.get(ā€˜articleā€™).get(ā€˜nameā€™) it returns undefined. However if I run the very same code again in the console I get the desired result (the name of the article which belongs to said loan)!

I figured this might mean that when the page is loaded, the model (loan) doesnā€™t load its belongsTo(ā€˜articleā€™) data.

Thanks !

Hi @dca123, Iā€™ll take a stab at what I think is happening here:

It sounds to me like when you fetch a ā€œloansā€ document from the API, itā€™s NOT including the data for the related models. Not sure if this is intentional or not, but the API response has no data in the relationships on article/friend so no data will be loaded for those models. The behavior youā€™re seeing in the console can be explained because the relationships are async. Basically the first time you try and fetch it the data isnā€™t there, or at least isnā€™t all there (kinda seems like Ember Data may have half created a record based on the relationships hash included in the response but since there isnā€™t a record in there it canā€™t fully created it) so it returns undefined. Then in the background it does an async update/fetch to get the related model. So then by the time you do the second .get the related model is there as expected.

So to fix this, youā€™ll either want to actually include the related records in the payload on the payload (under data.relationships.article.data for example), like in the JSON API docs, or maybe look over the JSON API specs and make sure that including relationship links without the relationship data is what youā€™re supposed to do to support async relationship fetching correctly. I wish I could be more help there but Iā€™m not all that up on the JSON API spec. Put differently, if youā€™re actually trying to sideload the data, it needs to be included in the response. If not, be aware that async data fetching will occur on the first reference to the relationship, however Iā€™d expect it to return a promise and not undefined so maybe thereā€™s something going on with your API response that creates a ā€œpartial relationshipā€ somehow that you should remove.

1 Like

Thanks for your response ! I reviewed the JSON API requirements and it says that it MUST have either of a links or data object inside the relationship object. I just understood that an async relationship is one where ember tries to resolve the data in the relationship when it is first loaded. What I noticed what that when I first load the page the only makes a request to ā€˜friends/:friend_idā€™ and ā€˜friends/:friend_id/loansā€™ and doesnā€™t resolve one to ā€˜loans/:loan_id/articleā€™.

However when i type in the console temp0.get(ā€˜articleā€™).get(ā€˜nameā€™), it does make a request to ā€˜loans/:loan_id/articleā€™ and returns undefined. On the second attempt it doesnā€™t make the request since the data has been loaded and it merely displays the name of the article.

My question is why do you think that ember-data isntā€™t making a request for ā€˜loans/:loan_id/articleā€™ when Iā€™ve explicitly stated that async is true in the models ?

Edit: Ok so I solved this by changing the routes file for /loans/index.js to the following

model() {
return this.modelFor('friends/show').get('loans').then(function(loans) {
  return loans.forEach((loan) => {
    loan.get('article');
  });
});

}

This forces ember to load the related article to the given loan. However this causes the page loading to be delayed till all the articles are loaded.

Might there be a more effective way in which I can achieve this ?

Thanks !