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 theDestinationMatchRule
andChargeRule
objects in thehasMany
are not newly created records, calling.save()
on theDestination
record automatically tries to save the records in thehasMany
s, so the explicit child recorditem.save()
calls in mysave
method above are pre-empted in this case. (I think…this is a part I'm slightly less sure about)- When the
serializeBelongsTo
method of the serializer is called for theDestinationMatchRule
andChargeRule
records, thedestination
property of each is aDS.PromiseObject
, and the promise is unsettled. This results inserializeBelongsTo
addingdestination: undefined
to the JSON object, and ultimately in thedestination
property 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 then
ing 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?