ember-cli-mirage: Infinite loop when loading fixtures with relationships
I have the following models in my app:
// mirage/models/band.js
import { Model, hasMany } from 'ember-cli-mirage';
export default Model.extend({
songs: hasMany('song'),
});
// mirage/models/song.js
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
band: belongsTo('band'),
});
And a few fixtures:
// mirage/fixtures/bands.js
export default [
{ id: 1, name: 'Pearl Jam', songIds: [1, 2, 3, 4, 5] },
{ id: 2, name: 'Led Zeppelin', songIds: [6, 7, 8] },
(...
]
// mirage/fixtures/songs.js
export default [
{ id: 1, title: 'Daughter', rating: 5, bandId: 1 },
{ id: 2, title: 'Yellow Ledbetter', rating: 5, bandId: 1 },
{ id: 3, title: 'Animal', rating: 4, bandId: 1 },
{ id: 4, title: 'Inside Job', rating: 4, bandId: 1 },
{ id: 5, title: 'Who We Are', rating: 2, bandId: 1 },
(...)
]
When I load these fixtures in my app, they throw it in an infinite loop. I tracked it down to model._setupRelationships.
When the first band (Pearl Jam) is instantiated, it also instantiates (and calls _setupRelationships for) the related songs and each song then seems to instantiate the band again, and then the loop restarts.
I’m not sure if there is a way around this that also makes sure the relationships are correctly set up. If I comment out the band: belongsTo('band') from the song model, no infinite loop is produced but at the same time band.get('songs') is empty.
(I’m using version 0.2.0-beta.4 and the out-of-the-box ActiveModelSerializer for both models)
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 15 (9 by maintainers)
Ok, I see what’s going on now.
First, you can see from the console that only the bands are being loaded, and the additional songs aren’t being loaded on the initial request, nor are they being requested by your Ember app. So, there’s two things you could do here. First, you can sideload the songs with the bands on the initial request. To do this, generate a
bandserializer:and make it look something like this
This is saying, every time your Mirage mock server serializes a
bandmodel, include that band’s related songs. This would get the songs to load on the initial request.Alternatively, if you want to keep your models asynchronous, you need to provide a
linkshash with each model. That’s how async works - Ember needs to know where to fetch the related models.You could do this in your fixtures, something like this:
You could also do it in your serializer to save yourself from having to manage ids:
If you do this, you’ll notice that Ember will make the second request once your template iterates through the band’s songs. The request will fail, since that’s a second route you’ll need to mock in Mirage (i.e. it’s a new endpoint that your actual server must implement). It might look something like this:
The last thing to be aware of is that your app is using Ember Data’s RESTSerializer but your Mirage mock server is using ActiveModelSerializer. AMS is meant for an AMS-style backend, so you may run into some inconsistencies. If this is just for a demo app, I’d suggest going ahead and setting up your Ember app to use AMS. If there’s going to be an actual server, you should write your mock server in the same format of the real server.
Remember that the point of Mirage is to mock your actual server, so when thinking about async vs sync models, how much to load up front etc., it all depends on the actual app you’re building, and what the production server requirements will be.
Let me know if you need any more help!