DS.RESTAdapter: Robust Support for Parent->Child Hierarchies #724

Closed
wants to merge 1 commit into
from

Conversation

Projects
None yet
@ghempton
Member

ghempton commented Feb 11, 2013

We had the need in our app to save transactions in parent->child order to ensure foreign keys are present. This PR uses nested promises to resolve dependencies.

@bradleypriest

This comment has been minimized.

Show comment
Hide comment
@bradleypriest

bradleypriest Feb 12, 2013

Member

I'm just upgrading from version4 to version11 (yes I know it's a huge jump), does this mean the functionality to save a new object and have it's children save once the parent is returned has not been reimplemented yet?
Is there anything I can help with here?

Member

bradleypriest commented Feb 12, 2013

I'm just upgrading from version4 to version11 (yes I know it's a huge jump), does this mean the functionality to save a new object and have it's children save once the parent is returned has not been reimplemented yet?
Is there anything I can help with here?

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Feb 12, 2013

Member

@bradleypriest afaik it has not. I could definitely use some help with the tests.

Member

ghempton commented Feb 12, 2013

@bradleypriest afaik it has not. I could definitely use some help with the tests.

@thingista

This comment has been minimized.

Show comment
Hide comment
@thingista

thingista Feb 13, 2013

Gordon,

This is amazing stuff. Thank you so much for this.
I am trying to put together a simple Rails+Ember example app showing how to use this Relational adapter (hopefully it will help others coming from the same background as me).

Just one thing though: I am struggling with "delete" on a child. When {embedded : 'always'} is set, if you do:

comment.deleteRecord(); // Reusing your test example, with Post and Comments

the next time you commit the store, it only PUTs the whole post. The content of the PUT is correct (the deleted comment has been removed from the post) but the server will not now about the fact the comment was deleted.

Am I using this in a wrong way?

Thanks a lot
PJ

Gordon,

This is amazing stuff. Thank you so much for this.
I am trying to put together a simple Rails+Ember example app showing how to use this Relational adapter (hopefully it will help others coming from the same background as me).

Just one thing though: I am struggling with "delete" on a child. When {embedded : 'always'} is set, if you do:

comment.deleteRecord(); // Reusing your test example, with Post and Comments

the next time you commit the store, it only PUTs the whole post. The content of the PUT is correct (the deleted comment has been removed from the post) but the server will not now about the fact the comment was deleted.

Am I using this in a wrong way?

Thanks a lot
PJ

@thingista

This comment has been minimized.

Show comment
Hide comment
@thingista

thingista Feb 13, 2013

Gordon,

Testing further, it seems there is a bug when you add grand-children. I think it is here:

function createNestedPromise(node) {
  var promise = node.promise(store, adapter);
  if(node.children.length > 0) { // Culprit here: promise might be nil if !adapter.shouldSave(node.record), i.e. (I think?) if an ancestor of node.record has been marked for saving. It might happen if you have more than two "layers" of associations
    promise = promise.pipe(function() {
      var childPromises = Ember.A(node.children.map(createNestedPromise)).compact();
      return jQuery.when.apply(jQuery, childPromises);
    });
  }
  return promise;
}

Replacing by

if((node.children.length > 0) && (promise))

seems to work (sorry I did not manage to run your test suite, only my own ones).

PJ

Gordon,

Testing further, it seems there is a bug when you add grand-children. I think it is here:

function createNestedPromise(node) {
  var promise = node.promise(store, adapter);
  if(node.children.length > 0) { // Culprit here: promise might be nil if !adapter.shouldSave(node.record), i.e. (I think?) if an ancestor of node.record has been marked for saving. It might happen if you have more than two "layers" of associations
    promise = promise.pipe(function() {
      var childPromises = Ember.A(node.children.map(createNestedPromise)).compact();
      return jQuery.when.apply(jQuery, childPromises);
    });
  }
  return promise;
}

Replacing by

if((node.children.length > 0) && (promise))

seems to work (sorry I did not manage to run your test suite, only my own ones).

PJ

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Feb 13, 2013

Member

@thingista deleting an embedded child needs to be handled by your backend implementation. We inspect the params that are sent to the server and delete children that aren't present. We made a generic rails dsl that allows us to do this easily that we might open source eventually.

Member

ghempton commented Feb 13, 2013

@thingista deleting an embedded child needs to be handled by your backend implementation. We inspect the params that are sent to the server and delete children that aren't present. We made a generic rails dsl that allows us to do this easily that we might open source eventually.

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Feb 13, 2013

Member

@thingista also, if you could produce a test case for the bug you are hitting that would be a big help!

Member

ghempton commented Feb 13, 2013

@thingista also, if you could produce a test case for the bug you are hitting that would be a big help!

@thingista

This comment has been minimized.

Show comment
Hide comment
@thingista

thingista Feb 13, 2013

@ghempton I sent you a pull request with a test. I hope it is fine.

Thanks
PJ

@ghempton I sent you a pull request with a test. I hope it is fine.

Thanks
PJ

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Feb 13, 2013

Member

@thingista thanks! Merged it in and added a slightly different fix from the one your provided.

Member

ghempton commented Feb 13, 2013

@thingista thanks! Merged it in and added a slightly different fix from the one your provided.

@bradleypriest

This comment has been minimized.

Show comment
Hide comment
@bradleypriest

bradleypriest Feb 27, 2013

Member

I'm running into an issue where an object that belongs to multiple hasMany associations where one parent is new and another is existing where the child is being set as both a rootNode and a child node and is thus getting sent to the server twice (the first time without the parent_id). I'll try and put together a failing test soon

Member

bradleypriest commented Feb 27, 2013

I'm running into an issue where an object that belongs to multiple hasMany associations where one parent is new and another is existing where the child is being set as both a rootNode and a child node and is thus getting sent to the server twice (the first time without the parent_id). I'll try and put together a failing test soon

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Feb 27, 2013

Member

@bradleypriest ah I could see that happening. Shouldn't be too hard to fix once there is a test.

Member

ghempton commented Feb 27, 2013

@bradleypriest ah I could see that happening. Shouldn't be too hard to fix once there is a test.

@bradleypriest

This comment has been minimized.

Show comment
Hide comment
@bradleypriest

bradleypriest Feb 28, 2013

Member

@ghempton I can't seem to get it to fail in QUnit just yet, I have found what I think is another bug though.
ghempton#2

Member

bradleypriest commented Feb 28, 2013

@ghempton I can't seem to get it to fail in QUnit just yet, I have found what I think is another bug though.
ghempton#2

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Mar 1, 2013

Member

@bradleypriest Thanks for the test. Merged it in and pulled some logic in from #440 to fix the problem. 🍺

Member

ghempton commented Mar 1, 2013

@bradleypriest Thanks for the test. Merged it in and pulled some logic in from #440 to fix the problem. 🍺

@boy-jer

This comment has been minimized.

Show comment
Hide comment
@boy-jer

boy-jer Mar 6, 2013

@ghempton, thamks for working on this. Do you mind giving a short clue on how you inspect the params that are sent to the server and delete children that aren't present.

I am thinking of something like this in the rails controller, let's say the child is :book

#extract the child params (books) sent by emberjs from the parent params

   parent_params.extract!(:books) 

#store the extracted params in a variable

  book_params =  book_params[:books]

#iterate through the books_params variable and delete the child :id's not included in it

  books_params.each do |pn| 
      Book.destroy unless pn.include?(:id)
 end

Do you think there is a better way. thanks.

boy-jer commented Mar 6, 2013

@ghempton, thamks for working on this. Do you mind giving a short clue on how you inspect the params that are sent to the server and delete children that aren't present.

I am thinking of something like this in the rails controller, let's say the child is :book

#extract the child params (books) sent by emberjs from the parent params

   parent_params.extract!(:books) 

#store the extracted params in a variable

  book_params =  book_params[:books]

#iterate through the books_params variable and delete the child :id's not included in it

  books_params.each do |pn| 
      Book.destroy unless pn.include?(:id)
 end

Do you think there is a better way. thanks.

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Mar 6, 2013

Member

@boy-jer check out this gem we released which does exactly what you suggested: https://github.com/GroupTalent/embedded_associations

Member

ghempton commented Mar 6, 2013

@boy-jer check out this gem we released which does exactly what you suggested: https://github.com/GroupTalent/embedded_associations

@boy-jer

This comment has been minimized.

Show comment
Hide comment
@boy-jer

boy-jer Mar 6, 2013

@ghempton many thanks for releasing that gem. It will be helpful in my work.

boy-jer commented Mar 6, 2013

@ghempton many thanks for releasing that gem. It will be helpful in my work.

@tobiaswerner

This comment has been minimized.

Show comment
Hide comment
@tobiaswerner

tobiaswerner Mar 7, 2013

Aloha everybody, please see following setup.

App.Parent = DS.Model.extend({
oneChild: DS.belongsTo("App.OneChild"),
anotherChild: DS.belongsTo("App.AnotherChild")
});
App.OneChild = DS.Model.extend({
name: DS.attr("string")
});
App.AnotherChild = DS.Model.extend({
name: DS.attr("string")
});

Then I create the record in the routes model hook.

App.ParentNewRoute = Ember.Route.extend({
model: function() {
return App.Parent.createRecord({
    oneChild: App.OneChild.createRecord({}),
    anotherChild: App.AnotherChild.createRecord({})
  });
}
});

oneChild and anotherChild would be saved correctly via two POST to the server. But after that two POST to /parents would be made. Am I doing something wrong in setting the relationship the correct way or is this just a little bug? Unfortunately I didn't get my head wrapped around this so I'm not able to provide a pull request...
Thanks in advance for all advices...

Aloha everybody, please see following setup.

App.Parent = DS.Model.extend({
oneChild: DS.belongsTo("App.OneChild"),
anotherChild: DS.belongsTo("App.AnotherChild")
});
App.OneChild = DS.Model.extend({
name: DS.attr("string")
});
App.AnotherChild = DS.Model.extend({
name: DS.attr("string")
});

Then I create the record in the routes model hook.

App.ParentNewRoute = Ember.Route.extend({
model: function() {
return App.Parent.createRecord({
    oneChild: App.OneChild.createRecord({}),
    anotherChild: App.AnotherChild.createRecord({})
  });
}
});

oneChild and anotherChild would be saved correctly via two POST to the server. But after that two POST to /parents would be made. Am I doing something wrong in setting the relationship the correct way or is this just a little bug? Unfortunately I didn't get my head wrapped around this so I'm not able to provide a pull request...
Thanks in advance for all advices...

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Mar 7, 2013

Member

@tobiaswerner that looks like a bug. Could you do a favor and create a test case for this in hierarchies.js? This shouldn't be too hard to fix.

Member

ghempton commented Mar 7, 2013

@tobiaswerner that looks like a bug. Could you do a favor and create a test case for this in hierarchies.js? This shouldn't be too hard to fix.

@tobiaswerner

This comment has been minimized.

Show comment
Hide comment
@tobiaswerner

tobiaswerner Mar 7, 2013

@ghempton Will try tomorrow. I'm really new to all this stuff ;)

@ghempton Will try tomorrow. I'm really new to all this stuff ;)

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Mar 7, 2013

Member

@tobiaswerner actually on second thought, I think there might need to be an inverse relationship on the child. Can you try adding additional DS.belongsTo's to the children?

Member

ghempton commented Mar 7, 2013

@tobiaswerner actually on second thought, I think there might need to be an inverse relationship on the child. Can you try adding additional DS.belongsTo's to the children?

@tobiaswerner

This comment has been minimized.

Show comment
Hide comment
@tobiaswerner

tobiaswerner Mar 7, 2013

@ghempton Thanks for the support but this was sadly not the solution...
Now I got following error after the second POST of Parent:
Error: Attempted to handle event didCommit on App.Parent:ember382:null while in state rootState.loaded.saved. Called with undefined

@ghempton Thanks for the support but this was sadly not the solution...
Now I got following error after the second POST of Parent:
Error: Attempted to handle event didCommit on App.Parent:ember382:null while in state rootState.loaded.saved. Called with undefined

@Bouke

This comment has been minimized.

Show comment
Hide comment
@Bouke

Bouke Mar 8, 2013

@ghempton your PR is against an old master, any chance you get it rebased on the updated master? I tried, but it seems that createRecord does not return with a promise anymore, which fails when trying to pipe on that (undefined) promise.
Edit: this was due to a custom adapter, which didn't return the jQuery promises. However, now I'm also running into the same issue as @tobiaswerner. This only happens when I have two or more children (of different types).

Uncaught Error: Attempted to handle event `didCommit` on <App.Account:ember371:1> while in state rootState.loaded.saved. Called with undefined ember-data.js:3499
DS.StateManager.Ember.StateManager.extend.unhandledEvent ember-data.js:3499
superWrapper ember-1.0.0-rc.1.js:884
sendRecursively ember-1.0.0-rc.1.js:26024
sendRecursively ember-1.0.0-rc.1.js:26032
sendRecursively ember-1.0.0-rc.1.js:26032
sendRecursively ember-1.0.0-rc.1.js:26032
sendEvent ember-1.0.0-rc.1.js:26041
sendRecursively ember-1.0.0-rc.1.js:26034
sendRecursively ember-1.0.0-rc.1.js:26032
sendRecursively ember-1.0.0-rc.1.js:26032
sendRecursively ember-1.0.0-rc.1.js:26032
sendEvent ember-1.0.0-rc.1.js:26041
Ember.StateManager.Ember.State.extend.send ember-1.0.0-rc.1.js:26564
DS.Model.Ember.Object.extend.send ember-data.js:3594
DS.Model.Ember.Object.extend.adapterDidCommit ember-data.js:3668
DS.Store.Ember.Object.extend.didSaveRecord ember-data.js:1840
DS.Adapter.Ember.Object.extend.didSaveRecord ember-data.js:6773
DS.Adapter.Ember.Object.extend.didUpdateRecord ember-data.js:6806
(anonymous function) adapter.js:44
(anonymous function) ember-1.0.0-rc.1.js:4064
Ember.handleErrors ember-1.0.0-rc.1.js:401
invoke ember-1.0.0-rc.1.js:4062
tryable ember-1.0.0-rc.1.js:4252
Ember.tryFinally ember-1.0.0-rc.1.js:1039
Ember.run ember-1.0.0-rc.1.js:4256
ajax.success adapter.js:43
l jquery.min.js:2
c.fireWith jquery.min.js:2
T jquery.min.js:2
r jquery.min.js:2

Bouke commented Mar 8, 2013

@ghempton your PR is against an old master, any chance you get it rebased on the updated master? I tried, but it seems that createRecord does not return with a promise anymore, which fails when trying to pipe on that (undefined) promise.
Edit: this was due to a custom adapter, which didn't return the jQuery promises. However, now I'm also running into the same issue as @tobiaswerner. This only happens when I have two or more children (of different types).

Uncaught Error: Attempted to handle event `didCommit` on <App.Account:ember371:1> while in state rootState.loaded.saved. Called with undefined ember-data.js:3499
DS.StateManager.Ember.StateManager.extend.unhandledEvent ember-data.js:3499
superWrapper ember-1.0.0-rc.1.js:884
sendRecursively ember-1.0.0-rc.1.js:26024
sendRecursively ember-1.0.0-rc.1.js:26032
sendRecursively ember-1.0.0-rc.1.js:26032
sendRecursively ember-1.0.0-rc.1.js:26032
sendEvent ember-1.0.0-rc.1.js:26041
sendRecursively ember-1.0.0-rc.1.js:26034
sendRecursively ember-1.0.0-rc.1.js:26032
sendRecursively ember-1.0.0-rc.1.js:26032
sendRecursively ember-1.0.0-rc.1.js:26032
sendEvent ember-1.0.0-rc.1.js:26041
Ember.StateManager.Ember.State.extend.send ember-1.0.0-rc.1.js:26564
DS.Model.Ember.Object.extend.send ember-data.js:3594
DS.Model.Ember.Object.extend.adapterDidCommit ember-data.js:3668
DS.Store.Ember.Object.extend.didSaveRecord ember-data.js:1840
DS.Adapter.Ember.Object.extend.didSaveRecord ember-data.js:6773
DS.Adapter.Ember.Object.extend.didUpdateRecord ember-data.js:6806
(anonymous function) adapter.js:44
(anonymous function) ember-1.0.0-rc.1.js:4064
Ember.handleErrors ember-1.0.0-rc.1.js:401
invoke ember-1.0.0-rc.1.js:4062
tryable ember-1.0.0-rc.1.js:4252
Ember.tryFinally ember-1.0.0-rc.1.js:1039
Ember.run ember-1.0.0-rc.1.js:4256
ajax.success adapter.js:43
l jquery.min.js:2
c.fireWith jquery.min.js:2
T jquery.min.js:2
r jquery.min.js:2

@thingista thingista referenced this pull request in getoutreach/data Mar 22, 2013

Open

Failing many-to-many test #1

@thingista

This comment has been minimized.

Show comment
Hide comment
@thingista

thingista Mar 25, 2013

@Bouke @tobiaswerner Just a quick note: I was running into similar issues as you guys and spent hours in the ember-data code trying to figure out what was wrong (sometimes these error messages are a bit cryptic). It turned out there was a binding somewhere in my code that was triggering during the "save" process, and altering objects that were being saved. Once I removed this binding everything was fine.

@Bouke @tobiaswerner Just a quick note: I was running into similar issues as you guys and spent hours in the ember-data code trying to figure out what was wrong (sometimes these error messages are a bit cryptic). It turned out there was a binding somewhere in my code that was triggering during the "save" process, and altering objects that were being saved. Once I removed this binding everything was fine.

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Apr 16, 2013

Member

@igorT @tomdale I would like to put more work into this PR if you think it is a candidate to be merged. Thoughts?

Member

ghempton commented Apr 16, 2013

@igorT @tomdale I would like to put more work into this PR if you think it is a candidate to be merged. Thoughts?

@tomdale

This comment has been minimized.

Show comment
Hide comment
@tomdale

tomdale Apr 19, 2013

Member

This is definitely an issue that we need to resolve ASAP. If it's possible, I'd like to solve the issue with less code than this spike requires—but we definitely need to solve it.

Member

tomdale commented Apr 19, 2013

This is definitely an issue that we need to resolve ASAP. If it's possible, I'd like to solve the issue with less code than this spike requires—but we definitely need to solve it.

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Apr 19, 2013

Member

I'm not sure what a more concise implementation would look like. Could definitely be trimmed down if we removed bulk support, but that works so why? I think @stefanpenner's work on rsvp will create some niceties here.

Member

ghempton commented Apr 19, 2013

I'm not sure what a more concise implementation would look like. Could definitely be trimmed down if we removed bulk support, but that works so why? I think @stefanpenner's work on rsvp will create some niceties here.

@stefanpenner

This comment has been minimized.

Show comment
Hide comment
@stefanpenner

stefanpenner Apr 19, 2013

Member

@tomdale agreed we want this soon. I am planning another push on the promise stuff this weekend, to continue where I left off wednesday evening. Once this work is in place @ghempton I are going to push for this asap.

Member

stefanpenner commented Apr 19, 2013

@tomdale agreed we want this soon. I am planning another push on the promise stuff this weekend, to continue where I left off wednesday evening. Once this work is in place @ghempton I are going to push for this asap.

@stefanpenner

View changes

packages/ember-data/tests/integration/hierarchies_test.js
+ store.commit();
+ equal(get(post, 'comments.firstObject'), comment, "post's comments should include comment");
+
+ waitForPromises(function() {

This comment has been minimized.

@stefanpenner

stefanpenner May 2, 2013

Member

rather then these "waitForPromises" should we be using the thenable returned by store.commit ?

@stefanpenner

stefanpenner May 2, 2013

Member

rather then these "waitForPromises" should we be using the thenable returned by store.commit ?

@heartsentwined

This comment has been minimized.

Show comment
Hide comment
@heartsentwined

heartsentwined May 17, 2013

Contributor

@ghempton do you have some sample code, where you createRecord() on a simple parent-hasMany-children (and child-belongsTo-parent) relationship? I tried this PR, it does send requests in the expected order (children after parent), but when I examine the data being sent, the parent_id field (in all children) in the post /children request is still 0. The POST /parent is returning a parent with the correct ID, though, just that this "new" ID is not updated into the child request.

Contributor

heartsentwined commented May 17, 2013

@ghempton do you have some sample code, where you createRecord() on a simple parent-hasMany-children (and child-belongsTo-parent) relationship? I tried this PR, it does send requests in the expected order (children after parent), but when I examine the data being sent, the parent_id field (in all children) in the post /children request is still 0. The POST /parent is returning a parent with the correct ID, though, just that this "new" ID is not updated into the child request.

@heartsentwined

This comment has been minimized.

Show comment
Hide comment
@heartsentwined

heartsentwined May 20, 2013

Contributor

@ghempton never mind, I didn't realize I was on the wrong branch all along. Today I checked out relational-adapter, and it's working as expected. Just ignore my post above.

Contributor

heartsentwined commented May 20, 2013

@ghempton never mind, I didn't realize I was on the wrong branch all along. Today I checked out relational-adapter, and it's working as expected. Just ignore my post above.

@raytiley

This comment has been minimized.

Show comment
Hide comment
@raytiley

raytiley May 23, 2013

I would really love to try this out, but I can't get this PR to apply to master. Does anyone have a current build with this applied?

Thanks!

I would really love to try this out, but I can't get this PR to apply to master. Does anyone have a current build with this applied?

Thanks!

@raytiley

This comment has been minimized.

Show comment
Hide comment
@raytiley

raytiley May 24, 2013

@ghempton I played around with this yesterday. It looks really promising. I did run into one issue. I'm trying to add a test that recreates it but I thought I would see if you had any initial ideas. My use case is like this:

App.Playlist = DS.Model.extend({
  clips: DS.hasMany('App.Clip'),
});

App.Clip = DS.Model.extend({
  playlist: DS.belongsTo('App.Playlist'),
  media: DS.belongsTo('App.Media'),
});

App.Media = DS.Model.extend({
});

Its essentially a one direction hasMany with a joining relationship. If I create a new Playlist with associated clips and media and call commit() on the store the Clip model only has one of its ids set (the playlist_id). If I pull the Playlist out into its own transaction and then commit that and then commit the defaultTransaction everything seems to work ok.

I'll try to reproduce this in a test over the weekend.

Thanks for the work!

@ghempton I played around with this yesterday. It looks really promising. I did run into one issue. I'm trying to add a test that recreates it but I thought I would see if you had any initial ideas. My use case is like this:

App.Playlist = DS.Model.extend({
  clips: DS.hasMany('App.Clip'),
});

App.Clip = DS.Model.extend({
  playlist: DS.belongsTo('App.Playlist'),
  media: DS.belongsTo('App.Media'),
});

App.Media = DS.Model.extend({
});

Its essentially a one direction hasMany with a joining relationship. If I create a new Playlist with associated clips and media and call commit() on the store the Clip model only has one of its ids set (the playlist_id). If I pull the Playlist out into its own transaction and then commit that and then commit the defaultTransaction everything seems to work ok.

I'll try to reproduce this in a test over the weekend.

Thanks for the work!

@stefanpenner

This comment has been minimized.

Show comment
Hide comment
@stefanpenner

stefanpenner May 24, 2013

Member

@raytiley a failing test case, and a fix (if possible) would be great. I hope to get this PR in as time permits.

Member

stefanpenner commented May 24, 2013

@raytiley a failing test case, and a fix (if possible) would be great. I hope to get this PR in as time permits.

@raytiley

This comment has been minimized.

Show comment
Hide comment
@raytiley

raytiley May 25, 2013

@stefanpenner @ghempton I just opened a pull request against ghemptons repo.

ghempton#4

The test fails by timing out, and I haven't yet figured out why. I figured I would throw it up just to see if someone else's eyes catch the problem quicker than my own. I'll keep investigating as best I can, but this is pretty deep for me, and I'm still getting used to the code.

Thanks

@stefanpenner @ghempton I just opened a pull request against ghemptons repo.

ghempton#4

The test fails by timing out, and I haven't yet figured out why. I figured I would throw it up just to see if someone else's eyes catch the problem quicker than my own. I'll keep investigating as best I can, but this is pretty deep for me, and I'm still getting used to the code.

Thanks

@raytiley

This comment has been minimized.

Show comment
Hide comment
@raytiley

raytiley May 25, 2013

@stefanpenner @ghempton So I found the issue and just pushed a fix that doesn't really fix the underlying problem. I'll try to explain it here.

Lets say you have nodes A B and C. A and B are both parents to C. So in order to persist C properly you need IDs from both A and B.

The code in this pull request currently finds all the parent nodes and creates promise chains for them. In our example you would get two promise chains A -> C and B -> C. So in this case C gets persisted twice.

The code I just pushed ensures that no node ever gets more than one promise. So you'll likely get promise chains that look like A -> C and B. The problem here is that C isn't dependent on B anymore. Its a race condition that most times will end up in a failing ajax call.

What we really want is a promise chain that looks like (A & B) -> C.

Still trying to figure out the best way to do this. Hopefully someone smarter than me comes along :)

@stefanpenner @ghempton So I found the issue and just pushed a fix that doesn't really fix the underlying problem. I'll try to explain it here.

Lets say you have nodes A B and C. A and B are both parents to C. So in order to persist C properly you need IDs from both A and B.

The code in this pull request currently finds all the parent nodes and creates promise chains for them. In our example you would get two promise chains A -> C and B -> C. So in this case C gets persisted twice.

The code I just pushed ensures that no node ever gets more than one promise. So you'll likely get promise chains that look like A -> C and B. The problem here is that C isn't dependent on B anymore. Its a race condition that most times will end up in a failing ajax call.

What we really want is a promise chain that looks like (A & B) -> C.

Still trying to figure out the best way to do this. Hopefully someone smarter than me comes along :)

@heartsentwined heartsentwined referenced this pull request in heartsentwined/ember-auth-rails-demo Jun 11, 2013

Closed

The app is not remembering me #3

@pivotal-medici

This comment has been minimized.

Show comment
Hide comment
@pivotal-medici

pivotal-medici Jun 18, 2013

Contributor

Any idea when this would be ready to merge? This is a critical feature for most apps and this branch is now 6 weeks out of date.

-- AK/AB

Contributor

pivotal-medici commented Jun 18, 2013

Any idea when this would be ready to merge? This is a critical feature for most apps and this branch is now 6 weeks out of date.

-- AK/AB

@scalability

This comment has been minimized.

Show comment
Hide comment
@scalability

scalability Jun 19, 2013

ping. Ember-data really needs better parent-child relationship support. Where we at?

ping. Ember-data really needs better parent-child relationship support. Where we at?

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Jun 19, 2013

Member

I'm working on something big that will solve this and more... will post more info soon

Member

ghempton commented Jun 19, 2013

I'm working on something big that will solve this and more... will post more info soon

@rupurt

This comment has been minimized.

Show comment
Hide comment
@rupurt

rupurt Jun 19, 2013

Contributor

Awesome. Looking forward to trying it out on our @pivotal-medici project. Do you have a list of todo's before it can be merged?

Contributor

rupurt commented Jun 19, 2013

Awesome. Looking forward to trying it out on our @pivotal-medici project. Do you have a list of todo's before it can be merged?

@shaneardell

This comment has been minimized.

Show comment
Hide comment
@shaneardell

shaneardell Jul 5, 2013

@ghempton Definitely in need of this feature, looking forward to using it. Any updates?

@ghempton Definitely in need of this feature, looking forward to using it. Any updates?

@ghempton

This comment has been minimized.

Show comment
Hide comment
@ghempton

ghempton Jul 7, 2013

Member

I am tempted to close this PR. I have moved off of Ember Data and am now using Epf (which has the functionality of this PR and more). That is unless someone like @stefanpenner wants to take it over?

Member

ghempton commented Jul 7, 2013

I am tempted to close this PR. I have moved off of Ember Data and am now using Epf (which has the functionality of this PR and more). That is unless someone like @stefanpenner wants to take it over?

@michaelbaudino

This comment has been minimized.

Show comment
Hide comment
@michaelbaudino

michaelbaudino Jul 7, 2013

Is Ember-data going to be abandonned ? If not I guess we should leave this open, it's still a feature request, isn't it ?

Is Ember-data going to be abandonned ? If not I guess we should leave this open, it's still a feature request, isn't it ?

@robmonie

This comment has been minimized.

Show comment
Hide comment
@robmonie

robmonie Jul 22, 2013

Contributor

I just had a bit of a go at fixing this and would appreciate some feedback on my approach from anyone familiar with the issue. This solves the problem in my app for a single use case. I haven't tested it beyond that yet which is why i'm posting the solution as a gist. If anyone thinks that my approach is valid, i'll continue with this to support bulk commits and properly unit test it before creating a pull request.

The approach is based on observing the ids of records that have 'belongsTo' relationships that they depend on. Any records that depend on other records that don't have ids yet assigned apply an observer and defer their saving until the other record ids are resolved. It's quite likely i've missed various edge cases in this so i'd welcome any scenarios that people think this might not work under. If my approach is way off track, i'd prefer to find out earlier if possible.

https://gist.github.com/robmonie/6052753

EDIT: I've submitted a pull request with a test around some of the work done so far here - #1092

Contributor

robmonie commented Jul 22, 2013

I just had a bit of a go at fixing this and would appreciate some feedback on my approach from anyone familiar with the issue. This solves the problem in my app for a single use case. I haven't tested it beyond that yet which is why i'm posting the solution as a gist. If anyone thinks that my approach is valid, i'll continue with this to support bulk commits and properly unit test it before creating a pull request.

The approach is based on observing the ids of records that have 'belongsTo' relationships that they depend on. Any records that depend on other records that don't have ids yet assigned apply an observer and defer their saving until the other record ids are resolved. It's quite likely i've missed various edge cases in this so i'd welcome any scenarios that people think this might not work under. If my approach is way off track, i'd prefer to find out earlier if possible.

https://gist.github.com/robmonie/6052753

EDIT: I've submitted a pull request with a test around some of the work done so far here - #1092

@wycats

This comment has been minimized.

Show comment
Hide comment
@wycats

wycats Jul 25, 2013

Member

I am in favor of this PR. If somebody wants to bring it up to date, I'll happily pull it in.

No, Ember Data is not abandoned.

Member

wycats commented Jul 25, 2013

I am in favor of this PR. If somebody wants to bring it up to date, I'll happily pull it in.

No, Ember Data is not abandoned.

@rupurt

This comment has been minimized.

Show comment
Hide comment
@rupurt

rupurt Jul 25, 2013

Contributor

@tjohn and I have successfully brought this up to master. We've push it to our branch.

We have removed the run loop around save as indicated in this comment thread. What should we do with that?

Do you want us to submit a separate PR for this? It appears @ghempton has abandoned the patch because EPF meets his needs

Contributor

rupurt commented Jul 25, 2013

@tjohn and I have successfully brought this up to master. We've push it to our branch.

We have removed the run loop around save as indicated in this comment thread. What should we do with that?

Do you want us to submit a separate PR for this? It appears @ghempton has abandoned the patch because EPF meets his needs

@wycats

This comment has been minimized.

Show comment
Hide comment
@wycats

wycats Jul 25, 2013

Member

Can you submit an up-to-date PR? Should I close this PR?

Member

wycats commented Jul 25, 2013

Can you submit an up-to-date PR? Should I close this PR?

@wagenet

This comment has been minimized.

Show comment
Hide comment
@wagenet

wagenet Aug 10, 2013

Member

Superseded by #1095.

Member

wagenet commented Aug 10, 2013

Superseded by #1095.

@wagenet wagenet closed this Aug 10, 2013

@escalant3 escalant3 referenced this pull request in escalant3/ember-data-tastypie-adapter Feb 20, 2014

Closed

Add support for saving graphs of objects #10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment