How to reload hasMany relationship in ember-data with ember octane?

Viewed 448

After upgrading to Ember 3.21.2 from 3.9, reloading hasMany relationships is not working properly anymore. For example the following model hook to fetch editable contents for a user does not update the user model anymore.

model(params) {
    const { user } = this.modelFor('application')

    const requestParams = this.mapParams(params)

    return RSVP.hash({
      user,
      results: user.hasMany('editableContents').reload({
        adapterOptions: requestParams
      })
    })
  },

It still triggers requests, but it loads the same contents with every request, even after the request params have changed. Initially the request is sent to /users/:user_id/editable-contents?filter=......

After changing the adapter options it sends a request for each content to /contents/:content_id

We believe the .reload() function is to blame, because we found out that the .hasMany('editableContents').reload() does not jump to the findHasMany() hook in our application adapter, but instead calls findRecord() for each record.

We are using:

"ember-cli": "~3.21.2",
"ember-data": "~3.21.0"

Any help is appreciated. Thanks!

1 Answers

With the help of user sly7-7 on Ember's Discord server we got pointed in the right direction.

The real problem was that our payload was missing the "related" link, because a paginated payload does not contain that link. A missing related link wasn't a problem before a change in ember-data that implemented the following block that will never be called if payload.links.related is undefined:

if (payload.links) {
      let originalLinks = this.links;
      this.updateLinks(payload.links);
      if (payload.links.related) {
        let relatedLink = _normalizeLink(payload.links.related);
        let currentLink = originalLinks && originalLinks.related ? _normalizeLink(originalLinks.related) : null;
...
}

see: https://github.com/emberjs/data/blob/ff4f9111fcfa7dd9e39804ed17f5af27a4a01378/packages/record-data/addon/-private/relationships/state/relationship.ts#L633

As a workaround we overrode the normalizeArrayResponse() hook in our application serializer and set the related link to the base request link if there is no related link:

normalizeArrayResponse(store, primaryModelClass, payload, id, requestType) {
  if (payload.links && payload.links.first && !payload.links.related) {
    const baseLink = payload.links.first.split('?')[0]
    if (isRelationshipLink(baseLink)) {
      payload.links.related = baseLink
    }
  }
}

With that workaround, which also uses a rather hacky way to see if the link is a relationship link, the .reload() function works again globally in our application.

To be safe we will also see if we can send the related links with the backend response, which would be cleaner than above workaround.

Related