1

Given two models, how can I ensure that an update to the "child" object marks the "parent" object as "dirty" so that calling save on the parent object does not skip?


Details

Using ember-model, I have defined Person and Address models like so:

    App.Person  = Ember.Model.extend({
        id: Ember.attr(),
        name: Ember.attr('string'),
        address: Ember.belongsTo('App.Address', { key: 'address', embedded: true }),
    });

    App.Address = Ember.Model.extend({
        id: Ember.attr(),
        line1: Ember.attr('string'),
        line2: Ember.attr('string')
    });

Now I have rendered this in a form, and made these attributes editable:

            {{input value=model.name classNames="name"}}
            {{input value=model.address.line1 classNames="address-line1"}}
            {{input value=model.address.line2 classNames="address-line2"}}
            <button type='button' {{action 'save'}}>Save</button>
            <button type='button' {{action 'cancel'}}>Cancel</button>

So far so good. The last piece of the puzzle is persisting the model to server

    actions: {
        save: function() {
            var model = this.get('model');
            var address = model.get('address');
            console.log(
                "model.get('isDirty')=", model.get('isDirty'), //false
                "address.get('isDirty')=", address.get('isDirty') //true
            );
            model.save();
            model.get('address').save();
        },

        cancel: function() {
            var model = this.get('model');
            var address = model.get('address');
            console.log(
                "model.get('isDirty')=", model.get('isDirty'), //false
                "address.get('isDirty')=", address.get('isDirty') //true
            );
            address.revert();
            model.revert();
        }
    }

Here we see that when the user edits the address (either line1 or line2), the model is not considered to be "dirty", and thus ember-model does not make the adapter call to save().

This happens, even though address is considered to be dirty, and has a relationship defined with model.

This means that I need to call save (or revert) separately on the two objects. I would thus lose atomicity of the operation, and also need to define a new endpoint for the address objects. I do not want to do either of these.

How can I ensure that updating address will make model becomes dirty as well?


Update:

Instead of calling save on both the "child" and "parent" objects, I found a better way by looking through the source for ember-model:

            console.log(
                "model.get('isDirty')=", model.get('isDirty'), //false
                "address.get('isDirty')=", address.get('isDirty') //true
            );
            // model.get('address').save();
            if (address.get('isDirty')) {
                model._relationshipBecameDirty('address');
            }
            console.log(
                "model.get('isDirty')=", model.get('isDirty'), //true
                "address.get('isDirty')=", address.get('isDirty') //true
            );
            model.save();

This ensures atomicity is preserved, however calling a private method directly like this does not seem right. Is there a better way?

Currently the only usages of this method - _relationshipBecameDirty - are in has_many_array.js in ember-model, and I was not able to find any instance in belongs_to.js. If this is intentional by design in meber-model, what is the proper way to accomplish this?

bguiz
  • 27,371
  • 47
  • 154
  • 243

1 Answers1

0

First of all I'd include DS.hasOne('person') assuming two people don't have the same address (and their addresses change at the same time). And no need for the ID fields, they're implicit.

You have to call a private method because what your doing doesn't make sense for a RESTful database. Your changing the address, not the person! If you want to update ie. updated_at timestamp on Person, you'd want to do that on the server when address is updated. None of the attributes on person have changed, so ember is right in saying the record isn't dirty.

If you're creating a new address record you'll want to save the address first then set the new ID to the person, and then save person (which will be dirty). In that case you might be better of putting the belongsTo person on the address instead.

Ryan Taylor
  • 12,559
  • 2
  • 39
  • 34