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

[BUGFIX beta] Fix id property in DS.Model once and for all #3781

Merged
merged 1 commit into from
Sep 28, 2015

Conversation

acburdine
Copy link
Contributor

No description provided.

}
},

setId: Ember.observer('id', function () {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the tests bellow, we only update the ID via:

updateId: function(internalModel, data) {
var oldId = internalModel.id;
var id = coerceId(data.id);
Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + internalModel + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId);
this.typeMapFor(internalModel.type).idToRecord[id] = internalModel;
internalModel.setId(id);
},

which already calls internalModel.setId

What is the point of this observer? As model.get('id') should just be a CP that always reads internalModels id.

Lets remember that the data flows away from the source of truth, in this case the source of truth is InternalModel. And changing the id on a model directly (bypassing the stores public API for this) seems like an anti pattern.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what if someone needs to edit the id before saving a new model? That worked before 1.0.0-beta.19

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then a getter/setter pair does the trick.

model ... {
  get id()   { return this.internalModel.id }
  set id(id) { this.store.updateId(this.internalModel, id) }
}

internalModel.setId = function(id) {

  if (this.model && this.id !== id) { this.model.notifyPropertyChange(‘id’); } 
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I'm understanding you correctly, that was the first attempt with the whole object.defineproperty thing. That didn't work because of a bug in ember itself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ug the internal flow here seems very strange.

It really feels like it should be:

model ... {
  get id()   { return this.internalModel.id; }
  set id(id) { this.internalModel.id = id; }
}
internalModel .. {
  set id(newId) {
    var id = this._id,
    if (id === newId) { return; }

    this._id = newId;
    this.store.moveToId(this.type, id, newId);

    if (this.model) {
      this.model.notifyPropertyChange('id');
    }
  },

   get id() {
     return this._id;
   }
}
store ... {
  moveId(type, oldId, newId) {
    let map = this.typeMapFor(type).idToRecord;

    idToRecord[newId] = idToRecord[oldId];
    delete idToRecord[oldId];
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does make sense, but atm it would break when the id property is watched.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stefanpenner Trying out the code you provided I'm seeing model.id return the correct value however, model.get('id') appears to return a cached undefined value when the id property is watched by the template. I thought notifyPropertyChange would invalidate the cache...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the internalModel code, shouldn't this.model actually be this.record?

@stefanpenner
Copy link
Member

@bmac on id update, do we not update old IDs in the identify map?

this.typeMapFor(internalModel.type).idToRecord[id] = internalModel;

Otherwise how to we prune the identify map correctly when a model is unloaded.

@bmac
Copy link
Member

bmac commented Sep 17, 2015

I don't think a record is slotted into the identity map by id until the id has been acknowledged by the server. This scenario is specifically for updating a record in the new state before it has been slotted into the identity map by id.

@stefanpenner
Copy link
Member

strange that unloading a record, transitions it to saved.deleted

@pangratz
Copy link
Member

strange that unloading a record, transitions it to saved.deleted

just a quick interception: maybe related #2870

@stefanpenner
Copy link
Member

just a quick interception: maybe related #2870

ya looks related, it seems sloppy that we are reusing the same state.

@acburdine
Copy link
Contributor Author

so.....what should I do to finish this?

@bmac
Copy link
Member

bmac commented Sep 17, 2015

@stefanpenner I made another attempt at using id as a ES5 getter/setter. Here are the 2 blockers I've hit so far.

First I tried using the code you provided and I found that this.record.notifyPropertyChange('id'); does not correctly update the _values object on Ember's meta object when id is a watched property. This means doing record.id returns the correct value but record.get('id') returns the old cached value.

Next I tried updating the code so store.updateId calls record.set('id', newId) and allowing the computed setter on id to update the internal model. This correctly updates the cached value in the meta object and both record.id and record.get('id') return the correct value when watched. However the id on internalModel is never updated because Ember ends up defining its own computed setter here that supplants the computed setter defined by ember data.

bmac added a commit that referenced this pull request Sep 28, 2015
[BUGFIX beta] Fix id property in DS.Model once and for all
@bmac bmac merged commit b19001a into emberjs:master Sep 28, 2015
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

Successfully merging this pull request may close these issues.

None yet

4 participants