From 40de87b9001b50ef0854b88c8c46281d47f22a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20K=C3=A4ufl?= Date: Mon, 14 Aug 2017 15:51:00 +0200 Subject: [PATCH] [BUGFIX release] Failing test for #5125 and attempted fix --- addon/-private/system/store.js | 29 ++++++++++++++++-------- tests/integration/records/unload-test.js | 28 +++++++++++++++++++++++ 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/addon/-private/system/store.js b/addon/-private/system/store.js index a75ee6cae5a..e1139f8ae30 100644 --- a/addon/-private/system/store.js +++ b/addon/-private/system/store.js @@ -1978,6 +1978,11 @@ Store = Service.extend({ return; } + let existingInternalModel = this._existingInternalModelForId(modelName, id); + + assert(`'${modelName}' was saved to the server, but the response returned the new id '${id}', which has already been used with another record.'`, + isNone(existingInternalModel) || existingInternalModel === internalModel); + this._internalModelsFor(internalModel.modelName).set(id, internalModel); internalModel.setId(id); @@ -2558,15 +2563,7 @@ Store = Service.extend({ assert(`You can no longer pass a modelClass as the first argument to store._buildInternalModel. Pass modelName instead.`, typeof modelName === 'string'); - let internalModels = this._internalModelsFor(modelName); - let existingInternalModel = internalModels.get(id); - - if (existingInternalModel && existingInternalModel.hasScheduledDestroy()) { - // unloadRecord is async, if one attempts to unload + then sync create, - // we must ensure the unload is complete before starting the create - existingInternalModel.destroySync(); - existingInternalModel = null; - } + let existingInternalModel = this._existingInternalModelForId(modelName, id); assert(`The id ${id} has already been used with another record for modelClass '${modelName}'.`, !existingInternalModel); @@ -2574,11 +2571,23 @@ Store = Service.extend({ // instances with the injections applied let internalModel = new InternalModel(modelName, id, this, data); - internalModels.add(internalModel, id); + this._internalModelsFor(modelName).add(internalModel, id); return internalModel; }, + _existingInternalModelForId(modelName, id) { + let internalModel = this._internalModelsFor(modelName).get(id); + + if (internalModel && internalModel.hasScheduledDestroy()) { + // unloadRecord is async, if one attempts to unload + then sync create, + // we must ensure the unload is complete before starting the create + internalModel.destroySync(); + internalModel = null; + } + return internalModel; + }, + buildInternalModel(modelName, id, data) { deprecate('buildInternalModel was documented as private and will be removed in the next version of Ember Data.', false, { id: 'ember-data.buildInternalModel', until: '2.17.0' }); return this._buildInternalModel(modelName, id, data); diff --git a/tests/integration/records/unload-test.js b/tests/integration/records/unload-test.js index abccbc90c24..81d7ba893b9 100644 --- a/tests/integration/records/unload-test.js +++ b/tests/integration/records/unload-test.js @@ -647,3 +647,31 @@ test("after unloading a record, the record can be fetched again soon there after assert.equal(internalModel.currentState.stateName, 'root.loaded.saved', 'We are loaded after findRecord'); }); + +test('after unloading a record, the record can be saved again immediately', function (assert) { + assert.expect(0); + + const store = env.store; + const data = { + data: { + type: 'person', + id: '1', + attributes: { + name: 'Adam Sunderland' + } + } + }; + + env.adapter.createRecord = () => Ember.RSVP.Promise.resolve(data); + + run(() => { + // add an initial record with id '1' to the store + store.push(data); + + // unload the initial record + store.peekRecord('person', '1').unloadRecord(); + + // create a new record that will again get id '1' from the backend + store.createRecord('person').save(); + }); +});