Ember.js & Ember Data: How to create record with hasMany relationship when the parent and child don’t exist yet

I’m just figuring this out myself, but I just did it this way and it works…

For starters, when you this.store.createRecord('basket', {}) it should come with an empty array for its fruits property. So, do this:

var basket = this.store.createRecord('basket', {});

basket.get('fruits').addObject(this.store.createRecord('fruit', {
    name: 'orange',
    color: 'orange'
}));

basket.get('fruits').addObject(this.store.createRecord('fruit', {
    name: 'banana',
    color: 'yellow'
}));

Incidentally, the empty fruits array is actually a DS.PromiseArray (which may instantly resolve to a DS.ManyArray?), a more specific subclass of Ember.Array, so that could make a difference.

However, what I found was that the fruits property wouldn’t get serialized at all–I’m using the JsonApiAdapter though, so that could be the reason. Or it might be that this is the expected behavior when the hasMany child objects haven’t been persisted yet. Anyway, I just did something like this in my controller’s actions.save method:

basket.save().then(function(){
    var promises = Ember.A();
    basket.get('fruits').forEach(function(item){
        promises.push(item.save());
    });
    Ember.RSVP.Promise.all(promises).then(function(resolvedPromises){
        alert('All saved!');
    });
});

Somehow, magically, when all that was done, I ended up with a saved “basket”, with a generated id, and saved “fruits” with generated ids. And, all the fruits’ belongsTo properties pointed back at the basket, and the basket’s hasMany contained all the fruits…despite the fact that, when I save()d the basket, the response from my backend returned an empty array for my fruits property, which I was sure would mess things up but somehow didn’t.

Of course, these weren’t my actual models, but the parallel was very close. I’m on Ember Data 1.0.0-beta5 and Ember 1.3.1. I’m not using the stock REST adapter, but the JsonApiAdapter is a pretty thin shell over it–so try this approach and see if it works!

Edit

I’ve opened a similar question here that addresses a problem I encountered using the above code to also update existing records (as opposed to creating new ones). That solution is more general and detailed but more complex.

Also, another potential gotcha I ran into is that when (in this example) the basket is created, the fruits property (which is a DS.PromiseArray) may not be fully ready yet. So you may need to do it like this instead:

var basket = this.store.createRecord('basket', {});

basket.get('fruits').then(function(){
    // Now the fruits array is available
    basket.get('fruits').addObject(this.store.createRecord('fruit', { /* ... */ }));
});

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)