Dan
Dan

Reputation: 1596

DS.hasMany causes a 'typekey' error when using Ember data

When I use 'hasMany' in a model referencing ember data (canary) stored in a fixture then I get this error...

Error while processing route: bookings Cannot read property 'typeKey' of undefined TypeError: Cannot read property 'typeKey' of undefined

The other examples I've seen on SO don't seem to be the exact same problem. I've tried to recreate the problem here, if you uncomment the 'hasMany' part in this example then it errors

http://emberjs.jsbin.com/yukahoduco/1/

App.Todo = DS.Model.extend({
  body: DS.attr('string')
  messages: DS.hasMany('message')
});

App.Message = DS.Model.extend({
    user: DS.attr('string'),
    subject: DS.attr('string')
});

App.Todo.FIXTURES = [
  {
    id: 1, 
    body: 'First Todo',
    messages: [{
      user: 'Harry',
      subject: 'Buy shaving cream'
    }]
  },
  {
    id: 2, 
    body: 'Second Todo',
    messages: [{
      user: 'Bob',
      subject: 'Buy razors'
    }]
  }
];

Upvotes: 1

Views: 276

Answers (2)

givanse
givanse

Reputation: 14943

Note: I tried this in your fiddle and it returned an error. I don't know if a breaking change occurred in newer versions or if its a bad combination of versions. However, I can tell you this code was tested locally with 1.7.0 and 1.0.0-beta.10 (the defaults for ember-cli 0.1.2)

Fixtures for a model:

Fixtures, for a FixtureAdapter, are not data coming into your application, its data that is already there. So, you are creating data at the class level (not model instance) i.e. you add records as if you were saving rows to a table.

App.Todo.FIXTURES = [
  {
    id: 1,
    body: "First Todo",
    messages: [100]
  },
  {
    id: 2, 
    body: "Second Todo",
    messages: [200]
  }
];

App.Message.FIXTURES = [
  {
    id: 100,
    "user": "Harry",
    "subject": "Buy shaving cream",
    todo: 1
  },
  {
    id: 200,
    "user": "Bob",
    "subject": "Buy razors",
    todo: 2
  }
];

export default Ember.Controller.extend({
  actions: {
    new: function() {
      var newRecord = this.store
                          .createRecord('todo', {
                             body: this.get('newBody'),
                             messages: [100]
                          });
    }
  }
}

);

Then, in your model you setup your relationship like this:

App.Todo = DS.Model.extend({
  body:     DS.attr('string'),
  // We need to set async: true for the FixtureAdapter to load the relations
  messages: DS.hasMany('message', { async: true })
});

var Message = DS.Model.extend({
  user:    DS.attr('string'),
  subject: DS.attr('string'),
  todo:    DS.belongsTo('todo')
});

When not setting a fixture for a model:

If you want to load your data with the format that is shown in the question:

{
  id: 1, 
  body: 'First Todo',
  messages: [{
    user: 'Harry',
    subject: 'Buy shaving cream'
  }]
}

You need to setup a serializer (DS.RESTSerializer or DS.JSONSerializer or DS.ActiveModelSerializer) that handles embedded data by passing to it a DS.EmbeddedRecordsMixin during creation. See: http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html

Upvotes: 1

GJK
GJK

Reputation: 37369

I believe that the following line is causing your issues:

user: DS.belongsTo('string')

There is no String model declared, so this is going to result in the error you posted when the container tries to look it up. The reason it's happening when you include the hasMany relationship on the Todo model is (I think) because that forces the Message model to be loaded, which causes the relationships to be loaded. Without the hasMany relationship, the Message model is never used and the error is never discovered.

Upvotes: 0

Related Questions