2
votes

This is a difficult situation to explain, since it's happening so pervasively in my project, but very often when I save my models, relationship fields (such as belongsTo) simply get erased in the persisted record.

I'm using couchdb, so I understand the problem is that each save replaces the old version of the record, and if all of the fields aren't sent with the save request they won't be in the latest version of the record. That's the problem, that it seems fields aren't correctly populated when the model is saved.

Is there a model attribute I can always check that will assure all of it's fields are ready to be pushed? I've tried to write a safe save that always checks isFulfilled, but that isn't reliably working. Often times, when I know which field is in danger of being overwritten, I can check for that relationship being fulfilled with a path like user.isFulfilled, but that isn't a very general solution, and isn't any good at all if there are multiple relationships at risk.

Also, since I'm using this couchdb adapter, I have a suspicion that these issues are normally handled by Ember Data but aren't being handled by that package.

I will be happy to provide code if asked! Like I said though, this is a pervasive problem.

Edit

I should also let you know my models are defined in a highly asynchronous manner. All of the relationship definitions are very similar to this:

user: DS.belongsTo('user', {async: true})

This means that my models very often have PromiseObjects of some sort, rather than normal objects. I've dealt with problems like this already (Cannot save model when using ember render helper) but again a more general solution would be great.

Edit

Here's what I've come up with:

function safeSave(model) {
    return new Ember.RSVP.Promise(function(resolve, reject) {
        attributes = [];
        model.eachRelationship(function(name, descriptor) {
            if (descriptor.kind == 'belongsTo') {
                attributes.push(name);
            }
        });

        var checkAttributes = function() {
            if (attributes.every(function(item) {return (model.get(item) === null) || !!model.get(item + '.isFulfilled');} )) {
                Ember.run.once(this, function() {
                    model.save().then(function(record){
                        console.log('Saved successfully.');
                        resolve(record);
                    }, function(error) {
                        console.log('Error while saving.');
                        reject(error);
                    });
                });
            }
        };
        checkAttributes();
        attributes.forEach(function(item) {
            if ((model.get(item) !== null) && !model.get(item + '.isFulfilled')) {
                model.addObserver(item + '.isFulfilled', function() {
                    if (model.get(item)) {
                        model.removeObserver(item);
                    }
                    checkAttributes();
                });
            }
        });
    });
};

It works in some situations, but not others. Is there a more elegant and safe way to make this happen?

1

1 Answers

1
votes

More than likely, this is due to known issues in Ember Data, such as:

https://github.com/emberjs/data/issues/1532