Right use of EmbeddedRecordsMixin?


#1

I’m trying to work with embedded records on saving and loading.

My code looks like this:

App.Poll = DS.Model.extend({
  title : DS.attr('string'),
  options : DS.hasMany('option', {async: true}),
});

App.Option = DS.Model.extend({
  title : DS.attr('string')
});

App.PollSerializer = DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, {
  attrs: {
    options: {embedded: 'always'}
  }
});

For testing reasons I’m using LSAdapter.

On saving the object to local storage every thing seems fine. The JSON looks like expected:

{
  "id": "snf3c",
  "title": "Title",
  "options": [
    {
      "title": "OptionA",
      "id":"1"
    }, {
      "title": "OptionB",
      "id":"2"
    }
  ]
}

But when loading the data from local storage I’m getting error messages.

First problem was that options did not had an id. I read here https://github.com/emberjs/data/pull/1234#issuecomment-27305845 that embedded data without id isn’t supported yet. So I added IDs for option manually on store.createRecord. That is where the IDs in JSON come from.

But now I get a new error saying:

Error while loading route: TypeError: Cannot read property 'options' of undefined
    at null.<anonymous> (file:///home/main/NetBeansProjects/croodle/lib/ember-data.js:9463:19)
    at file:///home/main/NetBeansProjects/croodle/lib/ember-data.js:6623:16
    at file:///home/main/NetBeansProjects/croodle/lib/ember.js:3165:16
    at Object.OrderedSet.forEach (file:///home/main/NetBeansProjects/croodle/lib/ember.js:3008:10)
    at Object.Map.forEach (file:///home/main/NetBeansProjects/croodle/lib/ember.js:3163:10)
    at Function.DS.Model.reopenClass.eachRelationship (file:///home/main/NetBeansProjects/croodle/lib/ember-data.js:6622:38)
    at updatePayloadWithEmbedded (file:///home/main/NetBeansProjects/croodle/lib/ember-data.js:9445:8)
    at DS.EmbeddedRecordsMixin.Ember.Mixin.create.extractSingle (file:///home/main/NetBeansProjects/croodle/lib/ember-data.js:9415:5)
    at superWrapper [as extractSingle] (file:///home/main/NetBeansProjects/croodle/lib/ember.js:1202:16)
    at null.extractFind (file:///home/main/NetBeansProjects/croodle/lib/ember-data.js:87:29) 

I have no idea why this error occurs. Is there a bug in EmbeddedRecordsMixin or did I use it wrong?

I’m new to EmberJS, so if I’m totally on the wrong way, please let me know.

Best regards


#2

The EmbeddedRecordsMixin is still beta like Ember Data is (I’ve made some improvements to it but ended up moving it to a separate project). The Transition guide says that embedded record support has been removed. The forked EmbeddedRecordsMixin can be found in this repo: ember-data-extensions

I recommend writing some QUnit tests for the issues you are running into so see how to improve/fix support for embedding records. You could fork ember-data-extensions and make your own adapter as well.

I’ve collected some of the documentation from the source code here: EmbeddedJSONMixin perhaps take a look at those examples.

Have you tried using a belongsTo relationship on the Option model?

App.Option = DS.Model.extend({
  title : DS.attr('string'),
  poll : DS.belongsTo('poll')
});

#3

Thanks for your fast reply.

I added belongsTo relationship on the Option model and tested with Ember Data Beta 1.0.4, but got the same error.

Then I tested your fork. I run in the same error. So I will write very detailed, what I have tested.

I used version with latest commit 6a2d9182465b4a20f7e5ac79f775f0effc95a16c. The tests extractSingle with embedded objects (hasMany relationship) and extractArray with embedded objects looks like my use case. In run make test. All tests passed. Then I used generated ember-data.js without the activemodel-adapter package, activemodel-adapter.js and embedded-records-mixin.js in my project. Still got the same error.

Finally I played with the tests and found the error. It is very important, that key of the array passed in JSON has the same name as the model.

This JSON will pass the test both for extractSingle and extractArray.

  var json_hash = {
    home_planet: {
      id: "1",
      name: "Umber",
      villains: [{
        id: "1",
        first_name: "Tom",
        last_name: "Dale"
      }]
    }
  };

This JSON will not pass the tests and generates the same error I got.

  var json_hash = {
    abc: {
      id: "1",
      name: "Umber",
      villains: [{
        id: "1",
        first_name: "Tom",
        last_name: "Dale"
      }]
    }
  };

I think LSAdapter (local storage of browser) passes the id of the model stored as key for the array. So it fails.

Is this defined by design of Ember Data or is it special to EmbeddedRecordsMixin? If I am not using EmbeddedRecordsMIxin I don’t get an error when using LSAdapter.

For my use case it will not be a problem to give a correct JSON back when switching to RESTAdapter. I am just using LSAdapter for developing, so I do not have to care about the server yet. But if I am right this behavior breaks compatibility of LSAdapter and EmbeddedRecordsMixin.