Using Ember's EmbeddedRecordsMixin for Nested JSON

Using ember-data's RESTSerializer it is pretty simple to integrate with a standard API and pull data. In my previous post I talked about what format the JSON needed to be in. For reference, let's look at it again.

{
  student: {
    id: 1,
    firstName: "Myles",
    lastName: "Kennedy"
  }
}

The ember model is just as straight forward.

import DS from 'ember-data';

export default DS.Model.extend({  
  firstName: DS.attr('string'),
  lastName: DS.attr('string')
});

But what happens when we add an embedded property makes things a bit more interesting. For example, adding an Address to our Student.

import DS from 'ember-data';

export default DS.Model.extend({  
  firstName: DS.attr('string'),
  lastName: DS.attr('string'),
  address: DS.belongsTo('address', { async: true })
});

Generally, this is the correct approach. If I am showing a Student and I want to view the Address, some action occurs and when I access student.address.xxx a request to the server will fetch the data I need from the API. In my case, I'm almost always showing the Student and Address together on the same request. So what happens is I get two requests when really, I only want to perform one and get all the data I need.

I changed my API so instead of

{
  student: {
    id: 1,
    firstName: "Myles",
    lastName: "Kennedy"
    address: {
      id: 1
    }
  }
}

I now return

{
  student: {
    id: 1,
    firstName: "Myles",
    lastName: "Kennedy"
    address: {
      id: 1,
      addressOne: "123 1st street",
      city: "Wichita",
      state: "KS",
      postalCode: "67202"
    }
  }
}

After removing { async: true } from the model and fetching the data again, I get the following somewhat cryptic error:

Assertion Failed: Passing classes to store methods has been removed. Please pass a dasherized string instead of undefined

Well, that's perfectly clear. As good as Ember is at producing decent error messages, this one left me stumped. After some googling and doc reading, I discovered that the RESTSerializer doesn't handle embedded JSON automatically. I had to modify the serializer to account for this and use the EmbeddedRecordsMixin.

import DS from 'ember-data';

export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {  
  attrs: {
    address: {embedded: 'always'}
  }
});

For my application, Address will always be embedded in Student. When the data is fetched from the API, ember now builds the model appropriately and doesn't need to make any additional calls to the server. Again, this use case may not be what is needed but I thought this might help someone else that runs into the fairly cryptic error message that I did.