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

Updating references that use internalModel to use recordData #324

Merged
merged 8 commits into from
Jan 21, 2019
Merged

Updating references that use internalModel to use recordData #324

merged 8 commits into from
Jan 21, 2019

Conversation

cohitre
Copy link
Contributor

@cohitre cohitre commented Jan 12, 2019

EmberData 3.5 introduced the RecordData object inside the InternalModel as a way to organize the internal state of models. This made this plugin incompatible with the more recent versions of EmberData #315

This PR is a first attempt at updating the plugin to be compatible with EmberData 3.7.

Some of the big changes in EmberData that I've encountered:

  • recordData now encapsulates _data, _attributes and _inFlightAttributes: I've updated all of the references to these three objects to go through _recordData. I've also moved the _fragments, _owner and _name properties into _recordData for consistency.
  • The InternalModel#flushChangedAttributes method doesn't exist anymore: It seems to have been replaced with willCommit, which is then delegated to _recordData. I am overriding willCommit directly on the RecordData prototype.

TODO:

  • Decorate the recordData overrides properly and remove the copy/pasted implementation.
  • Fix currentState assertion when creating a record with fragments.

@cohitre
Copy link
Contributor Author

cohitre commented Jan 12, 2019

The only snag that I am currently hitting is with this error showing up in some of the tests:

Error: 'currentState' is a reserved property name on instances of classes extending Model. Please choose a different property name for model:user

That error is triggered by the following line: https://github.com/emberjs/data/blob/v3.7.0/addon/-private/system/model/model.js#L1226. It seems to be because the currentState descriptor doesn't have the writable property set to on as expected by the isBasicDesc function: https://github.com/emberjs/data/blob/v3.7.0/addon/-private/system/model/model.js#L1182

I have ran this with a debugger statement and then set the writable property to true and I can confirm that all the tests pass under those circumstances. I am stumped as to what could be changing this property since nothing in the plugin seems to override that descriptor.

@cohitre
Copy link
Contributor Author

cohitre commented Jan 13, 2019

It seems like this assertion is only triggered when instantiating fragments on record creation. At some point when the fragment is set the currentState on the parent record is changed. The value of the currentState itself seems to be correct, but the property definition is not.

addon/ext.js Outdated

@method rollbackAttributes
*/
decorateMethod(InternalModelPrototype, 'rollbackAttributes', function rollbackFragments() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Deleting this method and moving its functionality into RecordData. InternalModel now delegates to the rollbackAttributes method in the recordData object.


@method flushChangedAttributes
*/
decorateMethod(InternalModelPrototype, 'flushChangedAttributes', function flushChangedAttributesFragments() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The functionality in this method seems to have been moved to willCommit


@method adapterDidCommit
*/
decorateMethod(InternalModelPrototype, 'adapterDidCommit', function adapterDidCommitFragments(returnValue, args) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved this functionality to recordData

@@ -164,24 +164,23 @@ FragmentRootState = wireState(FragmentRootState, null, 'root');
export default FragmentRootState;

export function fragmentDidDirty(record, key, fragment) {
if (!get(record, 'isDeleted')) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This can get called while the record is still being initialized, which causes the DS.Model#currentState to be overwritten with a new descriptor which then triggers an assertion in the DS.Model#init method. I am not sure what the consequences of accessing the currentState directly could be. Can we expect it to always be the canonical state?


// Don't reset if the record is new, otherwise it will enter the 'deleted' state
// NOTE: This case almost never happens with attributes because their initial value
// is always undefined, which is *usually* not what attributes get 'reset' to
if (!get(record, 'isNew')) {
if (!record.currentState.isNew) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any potential issues with accessing currentState directly? Would using internalModel._currentState be a better idea?

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like it should be ok

@erkie erkie mentioned this pull request Jan 15, 2019
@jakesjews
Copy link
Contributor

@workmanw this looks good to me how about you?

@cohitre
Copy link
Contributor Author

cohitre commented Jan 15, 2019

Now that all the tests are passing I have been testing this against my application. It seems to have introduced an issue where some shared references don't get setup correctly when loading the data.

The problem could be because of this update or because of the EmberData upgrade. I can reproduce that behavior with 3.5, 3.6 and 3.7. I'm investigating that issue and I'll update once I've figured out the cause.

@cohitre
Copy link
Contributor Author

cohitre commented Jan 17, 2019

After much debugging I've figured that the issue I was seeing was in my application and was a result of upgrading to EmberData 3.5. It seems like the behavior of inverse relationships is a bit different in EmberData 3.5 and I had to update some relationships that should've been set to null. This gives me added confidence on this PR.

It's important to note that this PR breaks compatibility with versions of EmberData before 3.5 and that it may be worth refactoring this to reduce the footprint of the core models that are extended.

  • Can the Model#willDestroy override be replaced with a RecordData#unloadRecord override?
  • Can the InternalModel#adapterDidError override be replaced with a RecordData#commitWasRejected override?

@jakesjews @workmanw How do you want to proceed?

@jakesjews
Copy link
Contributor

I'm ok with getting this merged then if its needed we can tweak the implementation. @workmanw how about you?

@workmanw
Copy link
Contributor

@jakesjews Looks good to me. I am not concerned about the backwards compat. That comes with the territory for this addon.

Thanks a ton for diving in @cohitre .

@jakesjews jakesjews merged commit c00e2b1 into adopted-ember-addons:master Jan 21, 2019
@jakesjews
Copy link
Contributor

@workmanw I think we should release this as version 4 so we don't catch anyone by surprise how about you?

@BnitoBzh
Copy link

BnitoBzh commented Jan 24, 2019

Merged, wonderful ! when the new version will be available (with README.md update) ?

@workmanw
Copy link
Contributor

Sorry, I'll try to get to this today. I got pulled into a bunch of issues yesterday.

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.

4 participants