gghh
gghh

Reputation: 23

How to add a new association to a record with ember.js?

I have two models that relate to each other like this:

I can't figure out how to make these association in an action of my route. Here my application template:

<script type="text/x-handlebars">
<p><button {{action 'save'}}>add data</button></p>
<ul>
{{#each country in model}}
<li>{{country.name}}
  <ul>
  {{#each city in country.cities}}
    <li>{{city.name}}</li>
  {{/each}}
  </ul>
</li>
{{/each}}
<ul>
</script>

my models are:

App.Countries = DS.Model.extend({
  name: DS.attr('string'),
  cities: DS.hasMany('cities', {async: true})
});

App.Cities = DS.Model.extend({
  name: DS.attr('string'),
  country: DS.belongsTo('countries', {async: true})
});

and here the application route:

App.ApplicationRoute = Ember.Route.extend({
    model: function() {
        return this.store.find('countries');
    },
    actions: {
        save: function() {
            var store = this.store;

            var country = store.createRecord('countries', {
                'name': 'France'
            });
            var city1 = store.createRecord('cities', {
                'name': 'Paris'
            });
            var city2 = store.createRecord('cities', {
                'name': 'Marseille'
            });

            country.get('cities').then(function(cities) {
                return cities.pushObject(city1);
            });
            country.get('cities').then(function(cities) {
                return cities.pushObject(city2);
            });

            city1.set('country', country);
            city2.set('country', country);

            country.save();
            city1.save();
            city2.save();
        }
    }
});

After the action "save" executes, I see in my ember inspector that the records are created, but seems like the associations don't work since the application template doesn't diplay them as I expect.

What's the right way to set association, then?

EDIT 3

For reasons that are still voodoo to me, even with the new implementation of DS.JSONSerializer.serializeHasMany, this strategy for saving records works

country.get('cities').then(function(cities){
  return cities.pushObjects([city1,city2]);
});
city1.set('country', country);
city2.set('country', country);

country.save();
city1.save();
city2.save();

but this doesn't:

country.get('cities').pushObjects([city1,city2]);
city1.set('country', country);
city2.set('country', country);

country.save();
city1.save();
city2.save();

EDIT 2

Turns out it's the very same problem as in the question Saving a model breaks one to many relationships. The alternative implementation of DS.JSONSerializer.serializeHasMany fixes it.

EDIT 1

@steve-h answers below, suggesting to not treat the cities property of the country record as a promise. This fails to work in a slightly different way:

country.get('cities').pushObjects([city1,city2]);
city1.set('country', country);
city2.set('country', country);

country.save();
city1.save();
city2.save();

seems like country never has links to the two cities: the <ul> in the application template doesn't visualize any city under the newly created country.

Inspecting further my original attempt, i.e.

country.get('cities').then(function(cities) {
  return cities.pushObject(city1);
});
country.get('cities').then(function(cities) {
  return cities.pushObject(city2);
});

city1.set('country', country);
city2.set('country', country);

country.save();
city1.save();
city2.save();

with a breakpoint somewhere in the above snippet, I get the following stacktrace

App.ApplicationRoute.Ember.Route.extend.actions.save (app.js:48)
triggerEvent                                         (ember.js:39606)
trigger                                              (ember.js:42157)
Router.trigger                                       (ember.js:41013)
EmberObject.extend.send                              (ember.js:39196)
Mixin.create.send                                    (ember.js:15451)
runRegisteredAction                                  (ember.js:34649)
-----> YAY !! at this point the associations are in place,
       and correctly displayed in the application template
Backburner.run                                       (ember.js:8160)
apply                                                (ember.js:7992)
run                                                  (ember.js:6626)
handleRegisteredAction                               (ember.js:34647)
(anonymous function)                                 (ember.js:22841)
x.event.dispatch                                     (jquery.js:5095)
v.handle                                             (jquery.js:4766)
-----> here the cities seems to disappear from the country record,
       and thus from the <ul> in the application template 

The overall effect is that the cities appear in my <ul> for a fraction of a second and then disappear. Here a jsbin with the live code.

Upvotes: 0

Views: 152

Answers (1)

Steve H.
Steve H.

Reputation: 6947

Your resolution of the promises is where I think you're getting hung up. The save is happening before the promises resolve (where you pushObject the city) . I haven't tried this, but I think you'll need to do something like this:

save: function() {
    var store = this.store;

    var country = store.createRecord('countries', {
        'name': 'France'
    });
    var city1 = store.createRecord('cities', {
        'name': 'Paris'
    });
    var city2 = store.createRecord('cities', {
        'name': 'Marseille'
    });

    country.get('cities').pushObjects([city1,city2]);

    city1.save();
    city2.save();
    country.save();
}

Upvotes: 1

Related Questions