From 6cfa604044b283e97f5b9b44fa760209a7bda95c Mon Sep 17 00:00:00 2001 From: Jordan Reimer Date: Wed, 20 Apr 2022 09:56:03 -0600 Subject: [PATCH] Generated Model Bug (#15099) * updates path help service to handle setting id of model * adds changelog entry * removes changelog entry --- ui/app/services/path-help.js | 29 +++++++- ui/app/utils/openapi-to-attrs.js | 2 +- .../templates/components/field-group-show.hbs | 2 +- ui/tests/unit/services/path-helper-test.js | 73 +++++++++++++++++++ 4 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 ui/tests/unit/services/path-helper-test.js diff --git a/ui/app/services/path-help.js b/ui/app/services/path-help.js index 8e51da5a5..1b2f94142 100644 --- a/ui/app/services/path-help.js +++ b/ui/app/services/path-help.js @@ -13,6 +13,7 @@ import fieldToAttrs from 'vault/utils/field-to-attrs'; import { resolve, reject } from 'rsvp'; import { debug } from '@ember/debug'; import { dasherize, capitalize } from '@ember/string'; +import { computed } from '@ember/object'; // eslint-disable-line import { singularize } from 'ember-inflector'; import { withModelValidations } from 'vault/decorators/model-validations'; @@ -270,7 +271,7 @@ export default Service.extend({ }, urlForCreateRecord(modelType, snapshot) { - const { id } = snapshot; + const id = snapshot.record.mutableId; // computed property that returns either id or private settable _id value const path = createPath.path.slice(1, createPath.path.indexOf('{') - 1); return `${this.buildURL()}/${apiPath}${path}/${id}`; }, @@ -279,6 +280,17 @@ export default Service.extend({ const path = deletePath.path.slice(1, deletePath.path.indexOf('{') - 1); return `${this.buildURL()}/${apiPath}${path}/${id}`; }, + + createRecord(store, type, snapshot) { + return this._super(...arguments).then((response) => { + // if the server does not return an id and one has not been set on the model we need to set it manually from the mutableId value + if (!response?.id && !snapshot.record.id) { + snapshot.record.id = snapshot.record.mutableId; + snapshot.id = snapshot.record.id; + } + return response; + }); + }, }); }, @@ -302,7 +314,8 @@ export default Service.extend({ const validations = fieldGroups.reduce((obj, element) => { if (element.default) { element.default.forEach((v) => { - obj[v.name] = [{ type: 'presence', message: `${v.name} can't be black` }]; + const key = v.options.fieldValue || v.name; + obj[key] = [{ type: 'presence', message: `${v.name} can't be blank` }]; }); } return obj; @@ -315,6 +328,18 @@ export default Service.extend({ } catch (err) { // eat the error, fieldGroups is computed in the model definition } + // attempting to set the id prop on a model will trigger an error + // this computed will be used in place of the the id fieldValue -- see openapi-to-attrs + newModel.reopen({ + mutableId: computed('id', '_id', { + get() { + return this._id || this.id; + }, + set(key, value) { + return (this._id = value); + }, + }), + }); newModel.reopenClass({ merged: true }); owner.unregister(modelName); owner.register(modelName, newModel); diff --git a/ui/app/utils/openapi-to-attrs.js b/ui/app/utils/openapi-to-attrs.js index 633a46339..4672e1471 100644 --- a/ui/app/utils/openapi-to-attrs.js +++ b/ui/app/utils/openapi-to-attrs.js @@ -29,7 +29,7 @@ export const expandOpenApiProps = function (props) { editType, helpText: description, possibleValues: prop['enum'], - fieldValue: isId ? 'id' : null, + fieldValue: isId ? 'mutableId' : null, fieldGroup: group || 'default', readOnly: isId, defaultValue: value || null, diff --git a/ui/lib/core/addon/templates/components/field-group-show.hbs b/ui/lib/core/addon/templates/components/field-group-show.hbs index a9d50800a..f82c0e389 100644 --- a/ui/lib/core/addon/templates/components/field-group-show.hbs +++ b/ui/lib/core/addon/templates/components/field-group-show.hbs @@ -3,7 +3,7 @@ {{#each-in fieldGroup as |group fields|}} {{#if (or (eq group "default") (eq group "Options"))}} {{#each fields as |attr|}} - {{#if (not-eq attr.options.fieldValue "id")}} + {{#if (not (includes attr.options.fieldValue (array "id" "mutableId")))}} openapiStub); + this.server.get('/auth/userpass/users/example', () => openapiStub); + this.server.post('/auth/userpass/users/test', () => { + assert.ok(true, 'POST request made to correct endpoint'); + return; + }); + + const modelType = 'generated-user-userpass'; + await this.pathHelp.getNewModel(modelType, 'userpass', 'auth/userpass/', 'user'); + const model = this.store.createRecord(modelType); + model.set('mutableId', 'test'); + await model.save(); + assert.equal(model.get('id'), 'test', 'model id is set to mutableId value on save success'); + }); +});