12

I'm experiencing somewhat of a bug with Ember/Ember-data. Here's my scenario:

  1. Client lands on / route and Ember loads data from /api/v1/videos?limit=8. The response comes from a rails-api backend using active_model_serializers which ensures the response is JSON API compliant. Now the store has 8 arbitrary videos loaded into it.

  2. Each video component in the DOM has a link to a user page (the video belongsTo a user and a user hasMany videos).

  3. Client clicks on a link-to which navigates to /users/1 which represents a user with ID 1

  4. The model hook for that route just loads a single user record. The user record has the following payload:

{
    "data": {
        "id": "1",
        "relationships": {
            "videos": {
                "data": [],
                "links": {
                    "related": "/api/v1/videos?user_id=1"
                }
            },
        },
        "type": "users"
    }
}

The problem is that ember does not automatically send the request for /api/v1/videos?user_id=1 (presumably because a similar request /api/v1/videos?limit=8 already happened).

If I directly load the /users/1 page then Ember is smart and auto-loads data from the /api/v1/videos?user_id=1 endpoint.

I suspect that Ember is being fooled by the fact that a similar request to the videos endpoint already happened with different query parameters. The end result is that my app does not show any data on the user page.

One way to fix this is to not use the links/related syntax but populate "data": [], with video IDs which will cause ember to send n requests for n videos. This works but is not acceptable for a large scale app where a user page might have hundreds of videos.

How can I fix this?

You can see that the active_model_serializers setup for the links/related structure is supposed to be tailored specifically for ember-data.


Edit: I tried getting rid of data: [] using include_data false in active_model_serializers which didn't help.


Edit 2: Here's the payload of /api/v1/videos?limit=8:

{
    "data": [
        ...
        {
            "attributes": {
                ...
            },
            "id": "325",
            "relationships": {
                "user": {
                    "data": {
                        "id": "1",
                        "type": "users"
                    }
                }
            },
            "type": "videos"
        },
        ...
    ]
}

In other words, some of the videos in that payload may belong to the user we will later load.


Edit 3: I'm doing this as a workaround in the user route:

afterModel(user) {
  user.hasMany('videos').reload();
})

It's kind of dumb but it gets the job done for now.


Edit 4: I've tried upgrading to ember and ember-data v3. The behavior persists.

Maros
  • 1,825
  • 4
  • 25
  • 56
  • Please Show The Payload Of `/api/v1/videos?limit=8` – Lux Jan 30 '18 at 08:09
  • I tested your example on my side and your use-case works for me. So it is no emberjs/data bug. Please check your link to users/show-page. Check if your users/show-model hook is called if you switch from videos-index to users/show. – wuarmin Feb 01 '18 at 19:11
  • @Lux @wuarmin I updated with the payload of `/api/v1/videos?limit=8`. I'm still having this issue. – Maros Feb 16 '18 at 02:14
  • Does this response has anything in the `included` property? – Lux Feb 16 '18 at 11:42
  • The `/api/v1/videos?limit=8` response? It does not. – Maros Feb 16 '18 at 18:42

2 Answers2

1

I created an Ember Twiddle with your use-case. Check it out to find the differences to your implementation. I'm very interested, why it doesn't work for you. I'm sure it's some small detail you're missing.


UPDATE

It turns out(see comments below), that emberjs/data, doesn't handle links.related-field if data-field(resource-linkage) is provided

relationships: {
  videos: {
    data: [], // if data is provided(resource linkage), ember won't fetch relationships via links.related
    links: {
      related: "/videos?user_id=4"
    }
  }
}

I can't find this restriction at JSON API DOC, so I think this is ember-specific, but this shouldn't be an issue, because data: [] makes no sense, if links-object is provided, so it should be omitted by the serializer.


wuarmin
  • 3,274
  • 3
  • 18
  • 31
  • Thanks for writing this. There is one detail your test code is missing (and maybe this is the cause of the problem): each user payload should have `data: [],` since that's how `active_model_serializers` seems to be forcing it. – Maros Feb 04 '18 at 19:16
  • You're welcome. You get an array as primary data for a findRecord? i.e.: `{ "data": [ { "type": "users", "id": "1", "attributes": {} } ] }`. If I do that I get following error: Ember Data expected the primary data returned from a 'findRecord' response to be an object but instead it found an array – wuarmin Feb 05 '18 at 14:52
  • 1
    The array is inside the `"relationships"` structure which seems to indicate an empty array of videos. It's the same as in the code snippet in my original question. – Maros Feb 05 '18 at 21:18
  • Ah, yes, that's the reason! Check if you can change your serializer-code. – wuarmin Feb 06 '18 at 07:24
  • `include_data false` did the trick: https://github.com/rails-api/active_model_serializers/pull/1454 – Maros Feb 09 '18 at 21:16
  • Actually, I'm looking at this again with real production data and the issue still occurs :( – Maros Feb 16 '18 at 02:05
  • @MarosHluska sorry for late reply! Do you solve your issues? please post your users-payload. – wuarmin Feb 23 '18 at 14:43
0

The existing answer provided by @wuarmin correctly identifies existing resource linkage (data: []) as causing the issue but does not explain what's going on. It sounds like as if it's an Ember Data issue but it's not.

Your response includes information about the related data in two forms:

  1. As a related resource link (links.related) and
  2. using resource linkage (data: []).

Having an empty array as value of resource linkage provides two information two information to consuming client:

  1. It's a has-many relationship.
  2. There aren't any related records.

As Ember Data already knows from response that there aren't any related records, it does not use the provided related resource link unless told explicitly to reload relationship data.

Returning an empty array as resource linkage if there are related records for that resource is simply wrong.

jelhan
  • 6,149
  • 1
  • 19
  • 35