From b7f7b7a9dce7f126c045c65277da8dc53cdd1e8b Mon Sep 17 00:00:00 2001 From: bmac Date: Thu, 23 Jul 2015 08:58:03 -0400 Subject: [PATCH] Use the correct modelClass and serializer to extract a polymorphic type when normalizing async relationships. Closes #3547 --- .../lib/serializers/rest-serializer.js | 19 ++++- .../serializers/rest-serializer-test.js | 79 ++++++++++++++++++- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/packages/ember-data/lib/serializers/rest-serializer.js b/packages/ember-data/lib/serializers/rest-serializer.js index 48e611d13ad..31070de71a5 100644 --- a/packages/ember-data/lib/serializers/rest-serializer.js +++ b/packages/ember-data/lib/serializers/rest-serializer.js @@ -149,7 +149,7 @@ var RESTSerializer = JSONSerializer.extend({ let serializer = store.serializerFor(modelName); arrayHash.forEach((hash) => { - let { data, included } = serializer.normalize(modelClass, hash, prop); + let { data, included } = this._normalizePolymorphicRecord(store, hash, prop, modelClass, serializer); documentHash.data.push(data); if (included) { documentHash.included.push(...included); @@ -159,7 +159,20 @@ var RESTSerializer = JSONSerializer.extend({ return documentHash; }, - /** + _normalizePolymorphicRecord(store, hash, prop, primaryModelClass, primarySerializer) { + let serializer, modelClass; + // Support polymorphic records in async relationships + if (hash.type && store._hasModelFor(this.modelNameFromPayloadKey(hash.type))) { + serializer = store.serializerFor(hash.type); + modelClass = store.modelFor(hash.type); + } else { + serializer = primarySerializer; + modelClass = primaryModelClass; + } + return serializer.normalize(modelClass, hash, prop); + }, + + /* @method _normalizeResponse @param {DS.Store} store @param {DS.Model} primaryModelClass @@ -241,7 +254,7 @@ var RESTSerializer = JSONSerializer.extend({ ``` */ if (isPrimary && Ember.typeOf(value) !== 'array') { - let {data, included} = this.normalize(primaryModelClass, value, prop); + let { data, included } = this._normalizePolymorphicRecord(store, value, prop, primaryModelClass, this); documentHash.data = data; if (included) { documentHash.included.push(...included); diff --git a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js index fd1b6fec768..30ffa0f7383 100644 --- a/packages/ember-data/tests/integration/serializers/rest-serializer-test.js +++ b/packages/ember-data/tests/integration/serializers/rest-serializer-test.js @@ -17,7 +17,9 @@ module("integration/serializer/rest - RESTSerializer", { superVillain: DS.belongsTo('super-villain', { async: false }), name: DS.attr('string') }); - YellowMinion = EvilMinion.extend(); + YellowMinion = EvilMinion.extend({ + eyes: DS.attr('number') + }); DoomsdayDevice = DS.Model.extend({ name: DS.attr('string'), evilMinion: DS.belongsTo('evil-minion', { polymorphic: true, async: true }) @@ -461,6 +463,81 @@ test('serializeIntoHash uses payloadKeyFromModelName to normalize the payload ro }); }); +test('normalizeResponse with async polymorphic belongsTo', function() { + env.registry.register('serializer:application', DS.RESTSerializer.extend({ + isNewSerializerAPI: true + })); + var store = env.store; + env.adapter.findRecord = () => { + return { + doomsdayDevices: [{ + id: 1, + name: "DeathRay", + links: { + evilMinion: '/doomsday-device/1/evil-minion' + } + }] + }; + }; + + env.adapter.findBelongsTo = () => { + return { + evilMinion: { + id: 1, + type: 'yellowMinion', + name: 'Alex', + eyes: 3 + } + }; + }; + run(function() { + store.findRecord('doomsday-device', 1).then((deathRay) => { + return deathRay.get('evilMinion'); + }).then((evilMinion) => { + equal(evilMinion.get('eyes'), 3); + }); + }); +}); + +test('normalizeResponse with async polymorphic hasMany', function() { + SuperVillain.reopen({ evilMinions: DS.hasMany('evil-minion', { async: true, polymorphic: true }) }); + env.registry.register('serializer:application', DS.RESTSerializer.extend({ + isNewSerializerAPI: true + })); + var store = env.store; + env.adapter.findRecord = () => { + return { + superVillains: [{ + id: "1", + firstName: "Yehuda", + lastName: "Katz", + links: { + evilMinions: '/super-villain/1/evil-minions' + } + }] + }; + }; + + env.adapter.findHasMany = () => { + return { + evilMinion: [{ + id: 1, + type: 'yellowMinion', + name: 'Alex', + eyes: 3 + }] + }; + }; + run(function() { + store.findRecord('super-villain', 1).then((superVillain) => { + return superVillain.get('evilMinions'); + }).then((evilMinions) => { + ok(evilMinions.get('firstObject') instanceof YellowMinion); + equal(evilMinions.get('firstObject.eyes'), 3); + }); + }); +}); + test("normalizeResponse can load secondary records of the same type without affecting the query count", function() { var jsonHash = { comments: [{ id: "1", body: "Parent Comment", root: true, children: [2, 3] }],