Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Got "RangeError: Maximum call stack size exceeded" for many to many relation #2116

Open
stukalin opened this issue Feb 10, 2021 · 8 comments

Comments

@stukalin
Copy link

stukalin commented Feb 10, 2021

The setup is the following: I have models called web, space and spaceview. Spaces and spaceviews are many-to-many and a web entity has lists of spaces and spaceviews. I use the REST serializer with the include method so that I want to return my spaces and spaceviews whenever I fetch webs.

I have a following acceptance test:

  test('visiting /web', async function(assert) {
    let space = this.server.create('space', {
      id: 1
    });

    let spaceview = this.server.create('spaceview', {
      id: 1,
      spaceIds: [1]
    });

    let web = this.server.create('web', {
      id: 1,
      spaceIds: [1],
      spaceviewIds: [1]
    })

    this.server.get('/webs', (s, r) => {
      return web;
    });

    await visit('/web');

    assert.equal(currentURL(), '/web');
  });

when I run it I've got my error
image

At the same time if I use a set of fixtures to load the same setup it works fine (in normal dev i mean).

It's possible that I setup my tests incorrectly, if that's the case any help would be appreciated. Otherwise it looks like a bug to me.

Sorry, saw the boilerplate link too late, I've created a small example app myself, here it is https://github.com/stukalin/embermiragetestselfreferences

Use the http://localhost:4200/tests to see the issue and the http://localhost:4200/web to see the same setup in dev environment with fixtures.

@stukalin
Copy link
Author

@samselikoff may I attract your attention? It sits here for a while already...

@samselikoff
Copy link
Collaborator

You're using RestSerializer which expects there to be models. Looks like you haven't defined any. If you haven't I'd recommend giving the ORM and Models sections of the docs a read.

@stukalin
Copy link
Author

@samselikoff as a matter of fact I have defined models (see https://github.com/stukalin/embermiragetestselfreferences/tree/master/app/models) and this setup works in normal (non-test) env. Or am I missing anything?

@cah-brian-gantzler
Copy link
Collaborator

Spent a few hours on this. Have tracked it down to this line https://github.com/miragejs/miragejs/blob/46fcd385ccc1495fb44b2aac92163a4eda2e0dab/lib/serializer.js#L403 At some point the included resources has no models, this causes the line a few down https://github.com/miragejs/miragejs/blob/46fcd385ccc1495fb44b2aac92163a4eda2e0dab/lib/serializer.js#L408 to create an empty array and that breaks it out of the loop. When you run tests, it always has a model. I have not yet found why the resource has no model (making it work). It seems to be it should always have a model and thus never work.

Will spend more time when I can but there is clearly some magic code that breaks it out.

Its not the didSerialize array, when it does work its checking against collection:space(1) and model:space(1) is in the array, actually a coupe times due to the collection/model difference. One would think the didSerialize array would be the one kicking it out of the loop, but its not.

@stukalin
Copy link
Author

stukalin commented May 18, 2021

@cah-briangantzler @samselikoff
I also spent a bit more time on this and now I know the difference between these 2 setups.

When I use my fixtures I don't explicitly create circular references, i.e. I declare my entities like this

let space = {
  id: 1
};

let spaceview = {
  id: 1,
  spaceIds: [2]
};

let web = {
  id: 1,
  spaceIds: [1],
  spaceviewIds: [1],
}

and ember (or is it still mirage?) is smart enough to realise that the space and the spaceview and the web are referring each other and they are reachable from each other.

Now when I try to create the same setup in my test

    let space = this.server.create('space', {
      id: 1
    });

    let spaceview = this.server.create('spaceview', {
      id: 1,
      spaceIds: [1]
    });

    let web = this.server.create('web', {
      id: 1,
      spaceIds: [1],
      spaceviewIds: [1]
    })

the following happens: when I add an entity which has a reference in an already declared entity then this already declared entity receives the ID of the new entity, i.e. after adding e.g. a spaceview my space would implicitly receive spaceviewIds: [1], same would happen with the web etc. The buildPayload apparently can't solve this and keeps adding the space and the spaceview in the queue until the stack overflows.

A possible workaround to this is not to create models via server.create but just return an object like this

    this.server.get('/webs', (s, r) => {
      return {
        web: {
          id: 1,
        },
        spaces: [{
          id: 1,
          web:1
        },{
          id: 2,
          web:1
        }],
        spaceviews: [{
          id: 1,
          spaces: [2],
          web:1
        },{
          id: 2,
          spaces: [1, 2],
          web:1
        }]
      }
    });

which is fine, but I'd prefer to use the server.create. Do my findings help to identify the problem and a possible workaround?

@cah-brian-gantzler
Copy link
Collaborator

Do you possibly have a repo with this data I could then step through and possibly see the problem.

First guess this would be in mirageJS not ember-cli-mirage, so posting an issue there may also get you a response

@stukalin
Copy link
Author

@cah-briangantzler yep, was in the original post: https://github.com/stukalin/embermiragetestselfreferences. Do you think I should duplicate the issue in the miragejs repo? I agree it really seems like to be more relevant there.

@cah-brian-gantzler
Copy link
Collaborator

I think you should, will be more likely to get Sams attention there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants