-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Zombie record when id query mismatch #1831
Zombie record when id query mismatch #1831
Conversation
If I query for a record of id `1` and the server returns a record of id `2` the store will have records of id `1` and id `2` as Ember Data pre-emptively instantiates the record you are querying for. A common use-case where this occurs is when querying for records of with a slug for an id. If I have a slug library server side for a Rails application I do not want to just map my id column for the slug because all of the relationships and foreign keys in my database are using the auto-incrementing id column, not the slugs. The slugs are there for presentation purposes only. However, on the client I will sometimes only ahve a slug as the unique identifier to search for a given record on the server. This PR will do the following: If you query the server for id `1` and it returns a record of id `2` it will delete the previously instantiated record of id `1`. If you already have a pre-existing record of id `1` that is committed and query the server for id `1` and the server returns a record of id `2` it will **not** delete the record of id `1`.
seems ok as a short-term fix. We really need to refactor the internals to just not create these zombie records... |
I have similar "zombie record" problem with belongsTo relationships. Will it fix it also? |
@@ -448,6 +448,13 @@ Store = Ember.Object.extend({ | |||
Ember.assert("You tried to find a record but your adapter (for " + type + ") does not implement 'find'", adapter.find); | |||
|
|||
var promise = _find(adapter, this, type, id); | |||
|
|||
promise.then(function(newRecord) { | |||
if (!record.get('isNew') && newRecord.get('id') !== record.get('id')) { |
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.
It seems like this would work if you created it locally, but what happens if you loaded it from the server? It still gets deleted, but that actually seems like a feature, because it enables you to locally delete things that were deleted on the server, though in a crappy way.
👍 overall |
@igorT I am OK making the changes if you'd like but it seemed from @stefanpenner's comments that the better solution is to actually refactor the internals to prevent zombie records from being created in the first place. |
I also vote for refactoring internals so zombie records are not created at all. |
I think if you express to the store that you believe that there exists a record with a certain id, it is ok to create that record locally and put it in a loading state. Once SSOT works, that record will also have relationship data on it if there are any relationships pointing towards it. If we remove the unloaded/loading record state, we will have to figure out how to guard against multiple finds triggering multiple GET requests, how to deal with a reloading record, etc. I am not convinced that the benefit is worth it to deal with this edge case. @stefanpenner thoughts? |
one approach is to have an identity map the promise of This both fixes the zombie record problem, and caches multiple requests for the same resource. |
Having the unloaded record that can have partial data on it is something I view as a feature. |
@igorT which feature? If the record is not yet realized, it may have falsey data as the server will respond with new data. If you have already created relationships based on a faulty idea, changing the id (when it returns from the server) wont propagate correctly. What is the downside to not having a tangible record until it is actually realized? |
The fact that you can have an unloaded record that has an id, but no payload yet. It allows you to manipulate it in and out of relationships. I don't see how we can support that if we lazily create the records only after find returns. |
unload would merely drop the promise from the identity map Manipulating its existence within arrays before the server acknowledges its existence seems dubious at best. Even this exact issue would fail horribly if the ID changed after the data has arrived if relationships have been created based on the originating ID. During a |
It's a often requested and a strong use case I feel. The ability to do
without having to fetch child. |
I think the strongest use case is that you got the id as the foreign key, in which case we still need the concept of unloaded records. Creating two different code paths one for user initiated find, and the other one for calling find from a belongsTo seem very complex. |
I would be reluctant to classify this as an edge case. Using slugs is a On Tuesday, May 20, 2014, Igor Terzic [email protected] wrote:
Brian Cardarella |
If you are querying by something that you know is not an id, maybe you should use findQuery? Or some equivalent of that that allows for overwriting urls nicely. |
I think this is a valuable use case to add to the url discussion: http://discuss.emberjs.com/t/nested-urls-for-ember-datas-restadapter-proposal/5290/ Your url is different than the canonical |
Do your backends support both the /slug and the /id routes? As currently the record that you get with the actual id will go to the /id route once you try saving it/reloading it. |
@igorT in Rails there are slug libraries that allow you to do: Person.find(params[:id]) The |
@bcardarella @igorT worth revisiting but not holding the v1.0.0-beta.9 release on this. |
If I query for a record of id
1
and the server returns a record of id2
the store will have records of id1
and id2
as Ember Datapre-emptively instantiates the record you are querying for.
A common use-case where this occurs is when querying for records with
a slug for an id. If I have a slug library server side for a Rails
application I do not want to just map my id column for the slug because
all of the relationships and foreign keys in my database are using the
auto-incrementing id column, not the slugs. The slugs are there for
presentation purposes only. However, on the client I will sometimes only
have a slug as the unique identifier to search for a given record on the
server.
This PR will do the following:
If you query the server for id
1
and it returns a record of id2
itwill delete the previously instantiated record of id
1
.If you already have a pre-existing record of id
1
that is committedand query the server for id
1
and the server returns a record of id2
it will not delete the record of id1
.