DS.Store automatically populates with Arrays but not Objects

I have an object in my server that looks like this:

{
   "apple": {
       "id": 1,
       "color": "red"
   },
   "oranges": [{
       "id": "1",
       "color": "Dark orange"
   }, {
       "id": "2",
       "color": "Light orange",
   }],
   "banana": {
       "id": 1,
       "color": "yellow"
   }
};

I have set up the appropriate and correct models as well in ember. My index route is this:

App.IndexRoute = Ember.Route.extend({
    model: function() {
      return this.store.find("apple", 1);
    }
});

Now, when I open the ember inspector and look at the ‘Data’ section, I see 3 models apple, oranges, and banana (as expected because I defined those models already). However, the number of records per model confuses me.

  • Apple shows 1 record, which is correct because I called for it in this.store.find;
  • Banana shows 0 records, which I believe is correct because I did not call for it, so it is not placed in the store;
  • Oranges, however, shows 2 records, one for each object in the array. I did not call for it in this.store.find.

Does anyone know why oranges is stored, but not banana? Also, I traced this problem through the debugger, and found the place in the code where the objects in the array are added in (the oranges objects), but not the single object (the banana object). It is on line 3010 in the ember-data.js file in the ‘extractSingle’ method.

 extractSingle: function(store, primaryType, payload, recordId, requestType) {
    payload = this.normalizePayload(primaryType, payload);

    var primaryTypeName = primaryType.typeKey,
        primaryRecord;

    for (var prop in payload) {
      var typeName  = this.typeForRoot(prop),
          type = store.modelFor(typeName),
          isPrimary = type.typeKey === primaryTypeName;

      // legacy support for singular resources
      if (isPrimary && Ember.typeOf(payload[prop]) !== "array" ) {
        primaryRecord = this.normalize(primaryType, payload[prop], prop);
        continue;
      }

      /*jshint loopfunc:true*/
      forEach.call(payload[prop], function(hash) {
        var typeName = this.typeForRoot(prop),
            type = store.modelFor(typeName),
            typeSerializer = store.serializerFor(type);

        hash = typeSerializer.normalize(type, hash, prop);

        var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord,
            isUpdatedRecord = isPrimary && coerceId(hash.id) === recordId;

        // find the primary record.
        //
        // It's either:
        // * the record with the same ID as the original request
        // * in the case of a newly created record that didn't have an ID, the
        //   first record in the Array
        if (isFirstCreatedRecord || isUpdatedRecord) {
          primaryRecord = hash;
        } else {
          store.push(typeName, hash);
        }
      }, this);
    }

    return primaryRecord;
  }

Essentially, on line 3022 (the ‘if (isPrimary && Ember.typeOf(payload[prop])’ line), it checks if the property type is the property type that was called for in ‘this.store.find’. If it is, add it in the store. On line 3028 however, if the property is an array, it iterates through it and places each object in the array into the store. Why is this?

Btw, I’m using ember-data 1.0.0-beta.7

I’m experiencing the same issue and I’m not sure why this is occurring. Any luck on this?

No luck. I guess you just have to be careful with the payload that is sent back.

I’m not sure for the exact reason behind this, but my hunch is that incase a property in ‘apple’ has a hasMany relationship with oranges, say something like this:

"apple": {
		"id": 1,
		"color": "red",
		"oranges": [1,2]
	}

Now, because we are sending up oranges as well, the store will be able to have access to those oranges. I assume because the ‘banana’ property is not an array, ember-data assumes it is not needed for a hasMany relationship, so discards it.

Again, this is just a hunch.

How do you define your mode here?

apple model:

// app/models/apple.js

import DS from 'ember-data';

var model = DS.Model.extend({
  color: DS.attr('string'),
  oranges: DS.hasMany('orange')
});

export default model;

orange model:

// app/models/orange.js

import DS from 'ember-data';

var model = DS.Model.extend({
  color: DS.attr('string')
});

export default model;