Can I POST hasMany children as an array of POJOs on the parent?

I have a form that currently saves a customer model that has a number of hasMany relationship to a number of other models.

Sometimes the ID of the customer model will be known and sometimes it won’t. In an ideal case I’d like to avoid creating a chain of thens() to save each model so thought I could send the entire object to the API as follows:

  {
    customer: {
      first_name: x,
      last_name: x,
      hasManyModel1: [{
        id: null,
        customer_id: null,       //Note: Sometimes I will be able to insert this manually. 
        content: x
      }, {
        id: null,
        customer_id: null,
        content: x
      }]
    }
  }

I can’t seem to get an array of objects to return under the ‘hasMany’ property though. I tried something like this:

    this.customer.hasManyModel1.pushObject(event)

    customer.save()

But the event object doesn’t seem to get pushed in the POST request. I tried various combinations of false and records in the models serialisers but didn’t have any luck. The only time I can get what I need is by creating a second property like newHasManyModel1 :[{},{}] which feels a bit naff.

Any feedback would be much appreciated. Let me know if I haven’t explained myself clearly enough.

Hi Abuelo,

There are a few separate concerns here:

  1. How does one create a record and also assign new data to its hasMany?
  2. How does one serialize a hasMany relationship as part of a payload
  3. How do you deal with a nested save

Your question so far is mostly around (1) and (2) but once you solve that you will realize you have issues with (3).

How does one create a record and also assign new data to its hasMany?

To establish relationships you can pass records into the call to createRecord. Something like this:

const order1 = store.createRecord('order', {});
const order2 = store.createRecord('order', {});
const customer = store.createRecord('customer', {
  firstName: 'Chris',
  lastName: 'Thoburn',
  orders: [ order1, order2 ]
});
await customer.save();

How does one serialize a hasMany relationship?

I’d start with reading the guide for serializers and the docs for the MinimumSerializerInterface https://api.emberjs.com/ember-data/release/modules/@ember-data%2Fserializer

These will explain both when you can expect the serializer method to be called and what it should return. In your case, you’re looking to implement the serialize() method and when serializing you’ll want to include the relationships in the manner you see fit.

How do you deal with a nested save

This is a hard problem. It’s especially hard for EmberData < 3.15 beta. It get’s slightly easier from 3.15 on.

For older versions your adapter needs to keep track of the original records in the hasMany/belongsTo, and assign the appropriate ID to them from the response before returning the overall payload. This is so that the payloads in the response get correctly associated with those records as the new data is populated into the store.

This will be all that is necessary for most cases but sometimes it may result in records still being in a dirty state, if so you need to implement a transactional save model in your API, I created an example of this here: https://ember-twiddle.com/bc93f1c525837420f7b14d8cdcb2d36a

For 3.15 beta you’d keep track of lid instead, and assign the original lid back onto the correct objects in the response either via your API or in your adapter. You shouldn’t need to do any of the transactional-save things in 3.15 beta+

You can see an example of this in EmberData’s own test suite here: https://github.com/emberjs/data/blob/master/packages/-ember-data/tests/integration/identifiers/lid-reflection-test.ts#L53-L77

Hope this helps!

Happy Trails.

5 Likes

Thanks @runspired for the detailed breakdown (and for responding to my other thread). Especially thanks for taking the time to twiddle that example, although it’s going to take a bit of time for me to fully understand it I can see the shape of what I’ll need to do.

Much appreciated!

1 Like