I can see record twice after createRecord() and save()


#1

I have an Ember app that works mostly as expected. But I’m not sure about how to understand following situation (= it is a bug or a feature) ?

Let’s have a simple model with (DS.attr(‘string’)) when I do .createRecord() and .save() I can see record immediately on the page (with expected flags). When the record is really saved there is still just one shown record. I thought that this will work every time but it is not true.

With a model which does not have any attribute only relationships:

 DS.Model.extend({
  constraintSet: DS.belongsTo('constraint-set'),
  resources: DS.hasMany('resource'),
 })

I can see it immediately after createRecord() [with hasDirtyAttributes as expected] but after save() is finished. I can see it on the page two times.

Can anyone help me to understand it? Or is it a bug?


#2

There’s something funny going on, for sure.

But, is there any chance you can share more of the code where you’re creating these records? And perhaps some examples of the response your getting back after you’ve saved?

One way this could happen, for example, is if you are manually creating your own id on the front-end. And then, when you save the record, the response from your server provides a different id. If that happens, ember-data will think that there are two different records when you had intended to only create one.

(This may not be what’s happening in your case)


#3

I have a repository on github and I can create a branch where this happens (currently, I’m deleting the old ones manually in the code). The backend is ember-cli-mirage.

Your hint was very useful. The issue is not in the two different IDs but in fact that I only store constraintSet from my ember code. So the ID is not updated because it is a different situation. In the response from mirage, I can see ‘included’ objects that contain relevant objects (with backend-generated ID) so I just have to find a proper way where to put the code to update IDs.


#4

Update) After my investigation, I’m not sure if what I want is possible at all. You have to depend on the fact that children records are returned (in included) in same order as they were entered. Then it should be possible to do it.

I have tried to set ‘id’ of children record (using .set(“id”, value)) in store but it ends up with having two records with the same ID.

I have tried to remove ‘included’ section at all. This looks promising but every relationship which is not included is fetched (_flushPendingFetchForType()) and I did not find a way how to easilly tell ember-data that version existing in the store is good enough. Yes, I can fake findRecord() but it does not look like a good idea.

The last but not very elegant version is to unloadRecords just before they should re-appear. That’s is how I have it right now.


#5

To make this work properly, you have to save each model which was involved in this relationship.

const newParentModel = this.store.createRecord('parent', { constrainSet: someConstrainSet, resources: [resource1, resource2] });
newParentModel
  .save()
  .then(() => resource1.save())
  .then(() => resource2.save())
  .then(() => someConstrainSet.save());

#6

Thanks for the response.

As I tried to say before the other records in relations are ‘stored/created’ at the backend [I have custom made adapter]. So there are no endpoints that can be used by resource1.save() ;; response itself contains those objects in ‘included’ section of JSON API. So I tried to find a way how to match them with originals without ID.


#7

Wonder if this might be useful: https://emberobserver.com/addons/ember-data-save-relationships (wether to use, or to take inspiration from).

It looks like you set a temporary __id__ property on the related models — and the serializer/adapter uses that to determine which of the models was actually saved. It’s not pretty, but it might do what you want.


#8

Great, thanks a lot. This is exactly how it should be solved. Using internal id looks simple enough and records are easy to update as we can identify them.