问题
Okay the obligatory information:
DEBUG: -------------------------------
DEBUG: Ember : 1.3.1
DEBUG: Ember Data : 1.0.0-beta.7.f87cba88
DEBUG: Handlebars : 1.0.0
DEBUG: jQuery : 1.10.2
DEBUG: -------------------------------
Here are the relevant models:
App.Destination = DS.Model.extend({
label: DS.attr('string'),
destinationMatchRules: DS.hasMany('destinationMatchRule', { async: true }),
chargeRules: DS.hasMany('chargeRule', { async: true }),
});
App.ChargeRule = DS.Model.extend({
startDate: DS.attr('date'),
endDate: DS.attr('date'),
costPerMinute: DS.attr('number'),
countryCode: DS.attr('string'),
label: DS.attr('string'),
connectionCost: DS.attr('number'),
destination: DS.belongsTo('destination', { async: true }),
});
App.DestinationMatchRule = DS.Model.extend({
pattern: DS.attr('string'),
priority: DS.attr('number'),
destination: DS.belongsTo('destination', { async: true }),
});
I have a destination.edit route/controller/template that lets me create or edit these all together. If I create a new set from scratch and hook them all up, I use this code to save everything:
save: function() {
var destination = this.get('content');
destination.save().then(function(){
var promises = Ember.A();
destination.get('destinationMatchRules').forEach(function(item){
promises.push(item.save());
});
destination.get('chargeRules').forEach(function(item){
promises.push(item.save());
});
Ember.RSVP.Promise.all(promises).then(function(resolvedPs){
alert('All saved!');
});
});
}
And it works! And there was much rejoicing.
However. If I use the same route and code to edit an existing graph--say I edit the destination's label and/or the destinationMatchRule's priority--I have big problems with both belongsTo('destination', { async: true }) relationships.
I've put breakpoints in my serializer's serializeBelongsTo method and all over my save method. It seems that the following is happening:
If theDestinationMatchRuleandChargeRuleobjects in thehasManyare not newly created records, calling.save()on theDestinationrecord automatically tries to save the records in thehasManys, so the explicit child recorditem.save()calls in mysavemethod above are pre-empted in this case. (I think…this is a part I'm slightly less sure about)- When the
serializeBelongsTomethod of the serializer is called for theDestinationMatchRuleandChargeRulerecords, thedestinationproperty of each is aDS.PromiseObject, and the promise is unsettled. This results inserializeBelongsToaddingdestination: undefinedto the JSON object, and ultimately in thedestinationproperty being dropped completely from the serialized JSON sent to the backend.
Naturally, this causes my backend to think that the destination object for the child records has been removed (which in my case causes a cardinality violation).
When I put logging statements near my explicit item.save() calls, I see instead that the DS.PromiseObject is settled, which is why I conclude what I described in #1 above. I first tried wrapping those calls in all manner of Ember.run.next callbacks to try to give the belongsTo time to settle, but if I'm correct about #1 that won't help anyway. But that also means I have no place to try and work around the problem!
Can somebody please help me figure this out--I'm so close and I think this may be the last battle in getting Ember Data to actually work and be used in an "ambitious" web application.
Edit
Correction, my conclusion about the order of operations here was incorrect. In fact I can make it work for both newly created graphs and editing existing ones by making my save method look like this:
save: function() {
var destination = this.get('content');
destination.save().then(function(){
//var promises = Ember.A();
destination.get('destinationMatchRules').forEach(function(item){
item.get('destination').then(function(){
item.save();
});
//promises.push(item.save());
});
destination.get('chargeRules').forEach(function(item){
item.get('destination').then(function(){
item.save();
});
});
//Ember.RSVP.Promise.all(promises).then(function(resolvedPs){
// alert('All saved!');
//});
});
}
BUT, this doesn't scale well: what if I had more belongsTo relationships? Might they all have to settle? Also it's now much harder to tell when the whole operation is complete--I can't add the item.save() returned promise to my promises array because it isn't created immediately (hints on this welcome in comments). And, should I be thening some other promise that I don't see, to make sure that the destination.save() is really really complete, and all the relationships have been propagated?
回答1:
Posting as an answer as this now seems a good general solution. But if this is necessary I'm really wondering if there is a way that's already in the code to handle it more succinctly and I'm duplicating something…
Nevertheless, here is what I'm doing to get around this, I created a new method on DS.Model called saveWhenSettled that returns a Promise:
DS.Model.reopen({
saveWhenSettled: function() {
var record = this;
return new Ember.RSVP.Promise(function(resolve, reject){
var promises = Ember.A();
record.eachRelationship(function(rel){
if(record.get(rel).then) promises.pushObject(record.get(rel));
});
Ember.RSVP.Promise.all(promises).then(function(){
record.save().then(function(result){
resolve(result);
}, function(reason){
reject(reason);
});
}, function(reason){
reject(reason);
});
});
}
});
Now I can just:
save: function() {
var destination = this.get('content');
destination.save().then(function(){
var promises = Ember.A();
destination.get('destinationMatchRules').forEach(function(item){
promises.push(item.saveWhenSettled());
});
destination.get('chargeRules').forEach(function(item){
promises.push(item.saveWhenSettled());
});
Ember.RSVP.Promise.all(promises).then(function(resolvedPs){
alert('All saved!');
});
});
}
So I get my completion notification back, and it automatically takes care of multiple relationships on the record needing to settle (which I've already run into since posting the question).
Again, I'd love for someone to tell me I've duplicated baseline code and I should do it another way.
A similar approach could probably be used to generalize my save method to auto-save all child relationships first, but I'll leave that as an exercise for the reader.
来源:https://stackoverflow.com/questions/22245793/belongsto-promise-is-unsettled-when-serializing-a-modified-record