Normalize embedded records with ember-data v1.0.0-beta.3


#1

I am trying to normalize data from REST API. I will not be changing the JSON response.

How do I generically munge this JSON response to pull out embedded records to make it so they are in a side-loaded format. This is also a SO question.

The response from the server looks like this:

{
  "objects": [
    {
      "active": true, 
      "admin": true, 
      "created_at": "2013-11-21T15:12:37.894390", 
      "email": "me@example.com", 
      "first_name": "Joe", 
      "id": 1, 
      "last_name": "Joeson", 
      "projects": [
        {
          "created_at": "2013-11-21T15:13:13.150572", 
          "id": 1, 
          "name": "Super awesome project", 
          "updated_at": "2013-11-21T15:13:13.150606", 
          "user_id": 1
        }
      ], 
      "updated_at": "2013-12-06T19:50:17.035881"
    }, 
    {
      "active": true, 
      "admin": false, 
      "created_at": "2013-11-21T17:53:17.155700", 
      "email": "craig@example.com", 
      "first_name": "Craig", 
      "id": 2, 
      "last_name": "Craigson", 
      "projects": [
        {
          "created_at": "2013-11-21T17:54:05.527790", 
          "id": 2, 
          "name": "Craig's project", 
          "updated_at": "2013-11-21T17:54:05.527808", 
          "user_id": 2
        }, 
        {
          "created_at": "2013-11-21T17:54:29.557801", 
          "id": 3, 
          "name": "Future ideas", 
          "updated_at": "2013-11-21T17:54:29.557816", 
          "user_id": 2
        }
      ], 
      "updated_at": "2013-11-21T17:53:17.155717"
    }
  ]
}

I want to change JSON payload so it looks like the JSON response, ember-data is expecting:I am trying to normalize data from REST API. I will not be changing the JSON response.

How do generically munge this JSON response to pull out embedded records to make it so they are in a side-loaded format. The response from the server looks like this:

{
  "objects": [
    {
      "active": true, 
      "admin": true, 
      "created_at": "2013-11-21T15:12:37.894390", 
      "email": "me@example.com", 
      "first_name": "Joe", 
      "id": 1, 
      "last_name": "Joeson",  
      "updated_at": "2013-12-06T19:50:17.035881"
      "projects": [1]
    }, 
    {
      "active": true, 
      "admin": false, 
      "created_at": "2013-11-21T17:53:17.155700", 
      "email": "craig@example.com", 
      "first_name": "Craig", 
      "id": 2, 
      "last_name": "Craigson", 
      "updated_at": "2013-11-21T17:53:17.155717"
      "projects": [2, 3]
    }
  ],
  "projects": [
    {
      "created_at": "2013-11-21T15:13:13.150572", 
      "id": 1, 
      "name": "Super awesome project", 
      "updated_at": "2013-11-21T15:13:13.150606", 
      "user_id": 1
    },
    {
      "created_at": "2013-11-21T17:54:05.527790", 
      "id": 2, 
      "name": "Craig's project", 
      "updated_at": "2013-11-21T17:54:05.527808", 
      "user_id": 2
    }, 
    {
      "created_at": "2013-11-21T17:54:29.557801", 
      "id": 3, 
      "name": "Future ideas", 
      "updated_at": "2013-11-21T17:54:29.557816", 
      "user_id": 2
    }
  ]
}

So far I am extending DS.RESTSerializer:

App.ApplicationSerializer = DS.RESTSerializer.extend({
    extractArray: function(store, type, payload, id, requestType) {
        var result = {};
        result[type.typeKey] = payload.objects;
        payload = result;

        return this._super(store, type, payload, id, requestType);
    },
    extractSingle: function(store, type, payload, id, requestType) {
        var result;
        var model = type.typeKey;

        if (payload.object) {
            result = payload.object;
        } else {
            result = payload;
        }

        var embedObjs, embedKey;

        type.eachRelationship(function(key, relationship) {
            if (relationship.kind === 'hasMany') { 
                embedKey = key;
                for (var i = 0; i < result[key].length; i++) {
                    result.key.push(result[key][i].id);
                }
                embedObjs = result[key].pop();
            }
        });

        payload[model] = result;

        if (!payload[embedKey])
            payload[embedKey] = [];

        payload[embedKey].push(embedObjs);

        return this._super(store, type, payload, id, requestType);
});

My models looks like this where a project belongs to a user:

App.User = DS.Model.extend({
	active: DS.attr(), 
	admin: DS.attr(),  
	email: DS.attr(), 
	firstName: DS.attr(),  
	lastName: DS.attr(),
	password: DS.attr(),
	createdAt: DS.attr(),  
	updatedAt: DS.attr(),
    projects: DS.hasMany('project')
});
App.Project = DS.Model.extend({
	createdAt: DS.attr(), 
	name: DS.attr(), 
	updatedAt: DS.attr(),
	userId: DS.belongsTo('user')
});

I am making a mistake somewhere, but I really don’t know where other than it’s in extractSingle. I get the following error in the JavaScript console, “Assertion failed: Error while loading route: TypeError: Cannot call method ‘toString’ of undefined.” My app is working without the relations.


#2

@drwlrsn you can use the DS.EmbeddedRecordsMixin or a fork of that which adds additional support for embedded records: ember-data-extensions