-
-
Notifications
You must be signed in to change notification settings - Fork 113
Fix for passing fragment arrays to fragments #364
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
base: master
Are you sure you want to change the base?
Fix for passing fragment arrays to fragments #364
Conversation
| this._pendingData = data; | ||
|
|
||
| let processedData = this._normalizeData(makeArray(data)); | ||
| let processedData = this._normalizeData(data instanceof StatefulArray ? copy(data) : makeArray(data)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@igorT added an instanceof check instead of using a specific property
|
|
||
| order.products.firstObject.set('name', 'Wolfsbane'); | ||
| assert.equal(order.products.firstObject.name, 'Wolfsbane', 'Modifies the original fragment array'); | ||
| assert.equal(user.orders.firstObject.products.firstObject.name, 'Tears of Lys', 'It does not modify the passed fragment array'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@richgt @igorT so it appears this approach this means we lose a reference to the fragment array when we pass it in and copy it. See this test where I modify the original array to have the value 'Wolfsbane' but the value of the product within the user model hasn't changed Tears of Lys. Only the original is changed.
Digging into this a bit more, the difference between this and the old master is that on these lines when we had a fragment array, we didn't call setupData instead we just assigned it directly to the property. This meant we didn't call normalizeFragmentArray.
With the recent refactor we are now always calling setupData which means we are now normalizing the fragment array, even when it's already set up
To tell you the truth I'm not entirely sure what is the right behavior here but possibly in the spirit of the original code it should just do a simple assignment instead of re-setting up the data? I guess the original code suffered from the problem where the wrong owner is assigned to the fragmentArray?
if (serverFragment instanceof StatefulArray) {
serverFragment[name] = data.attributes[name];
} else {
...
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@igorT @richgt I'm just wondering what's the best way to proceed here.
Solution 1
This PR in its current form.
- Does the
copybut breaks backward compatibility - Loses the reference to the fragmentArray you passed in
- The owner is set up correctly through
setupData
Solution 2
- Don't re-call
serverFragment.setupData(data.attributes[name])and instead just re-assign like we did pre-5.0. - Keeps the original reference to the fragment array
- Unfortunately the owner is now incorrect. The fragment array is still set to the initial owner. I’ve actually verified that this is existing behaviour pre-5.0 which to me seems like a bug.
Thinking about it my preference would be Solution 2, not requiring the copy, and keeping the reference. Could we augment solution 2 with also resetting the owner to be the correct one? Should we even bother considering this “bug” already existed? Not having lots of context on the refactor what's the downside to not calling serverFragment.setupData(data.attributes[name]); again.
Bringing this PR over from https://github.com/richgt/ember-data.model-fragments/pull/1 as I can't redirect the PR to a different repo.
@richgt @igorT This is a potential patch fix for the issue I mentioned I've been encountering with the
RecordDatarefactor.The use case
I previously mentioned:
This issue is also causing us a lot of problems in how we bootstrap our tests as we use Factory Guy quite heavily. We'll do something like the following a lot where
makewill create our models and model fragments for us. In the following examplegrandparent.parent.childrenis a fragment array.The problem
The specific problem appears to be that in current master when pass the
childrenfragment array to the new model it doesn't try and normalize the fragment array a second time, but in the refactor it does. The error it throws is the following if you try to pass a fragmentArray to another model.It seems that when we are getting to this line
when trying to set up the FragmentArray, the
instance ofcheck innormalizeFragmentArrayassertion is throwing. This is even though we are trying to add the correct type of fragment to the fragment array.The fix
Digging in the actual problem is that rather than passing the Fragment Array directly to
normalizeFragmentArraywe are actually passing a Fragment Array wrapped in another array. This is due to the following line https://github.com/richgt/ember-data.model-fragments/blob/ab24b0fbd4870ac129ed634eb82181758b86524c/addon/array/stateful.js#L72. We aren't checking whether the passeddatais already an array and are always wrapping it in one. My naive patch is to detect whether it's a fragment array and then copy it.