From 8cbc6dc3b76b313b6c10dfba5acf03ae2f89dec3 Mon Sep 17 00:00:00 2001 From: David Arvelo Date: Thu, 26 Jun 2014 22:35:25 -0400 Subject: [PATCH] Calls to POST API have include=tags closes #2998 - update PostSerializer to use DS.EmbeddedRecordsMixin - create PostAdapter to include include=tags in query params for POST and PUT - set include=tags for various GET post requests - change PostModel to have { embedded: always } instead of { async: true } - update Ember-Data to beta8 from beta7 - make call to get tags from model in editor.edit route synchronous since the tags now exist in the store - change casper test to wait for call to posts api with `?include=tags` --- bower.json | 2 +- core/client/adapters/post.js | 37 +++++++++++++++++++++ core/client/controllers/posts.js | 1 - core/client/models/post.js | 2 +- core/client/routes/editor/edit.js | 10 +++--- core/client/routes/posts.js | 1 + core/client/routes/posts/index.js | 3 +- core/client/routes/posts/post.js | 3 +- core/client/serializers/post.js | 54 +++++++++++++++++++++++++------ core/test/functional/base.js | 5 +-- 10 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 core/client/adapters/post.js diff --git a/bower.json b/bower.json index 88d5b2d85f..b5bd884e1d 100644 --- a/bower.json +++ b/bower.json @@ -5,7 +5,7 @@ "codemirror": "4.0.1", "Countable": "2.0.2", "ember": "1.5.0", - "ember-data": "~1.0.0-beta.7", + "ember-data": "~1.0.0-beta.8", "ember-load-initializers": "git://github.com/stefanpenner/ember-load-initializers.git#0.0.1", "ember-resolver": "git://github.com/stefanpenner/ember-jj-abrams-resolver.git#181251821cf513bb58d3e192faa13245a816f75e", "fastclick": "1.0.0", diff --git a/core/client/adapters/post.js b/core/client/adapters/post.js new file mode 100644 index 0000000000..a491a42c6c --- /dev/null +++ b/core/client/adapters/post.js @@ -0,0 +1,37 @@ +import ApplicationAdapter from 'ghost/adapters/application'; + +var PostAdapter = ApplicationAdapter.extend({ + createRecord: function (store, type, record) { + var data = {}, + serializer = store.serializerFor(type.typeKey), + url = this.buildURL(type.typeKey); + + // make the server return with the tags embedded + url = url + '?include=tags'; + + // use the PostSerializer to transform the model back into + // an array with a post object like the API expects + serializer.serializeIntoHash(data, type, record); + + return this.ajax(url, 'POST', { data: data }); + }, + + updateRecord: function (store, type, record) { + var data = {}, + serializer = store.serializerFor(type.typeKey), + id = Ember.get(record, 'id'), + url = this.buildURL(type.typeKey, id); + + // make the server return with the tags embedded + url = url + '?include=tags'; + + // use the PostSerializer to transform the model back into + // an array of posts objects like the API expects + serializer.serializeIntoHash(data, type, record); + + // use the ApplicationAdapter's buildURL method + return this.ajax(url, 'PUT', { data: data }); + } +}); + +export default PostAdapter; diff --git a/core/client/controllers/posts.js b/core/client/controllers/posts.js index 9387ab0155..02d91a1633 100644 --- a/core/client/controllers/posts.js +++ b/core/client/controllers/posts.js @@ -15,7 +15,6 @@ var PostsController = Ember.ArrayController.extend({ // published_at: DESC // updated_at: DESC orderBy: function (item1, item2) { - function publishedAtCompare() { var published1 = item1.get('published_at'), published2 = item2.get('published_at'); diff --git a/core/client/models/post.js b/core/client/models/post.js index 0de58e780a..f7de6b042f 100644 --- a/core/client/models/post.js +++ b/core/client/models/post.js @@ -22,7 +22,7 @@ var Post = DS.Model.extend(ValidationEngine, { updated_by: DS.belongsTo('user', { async: true }), published_at: DS.attr('moment-date'), published_by: DS.belongsTo('user', { async: true }), - tags: DS.hasMany('tag', { async: true }), + tags: DS.hasMany('tag', { embedded: 'always' }), //## Computed post properties isPublished: Ember.computed.equal('status', 'published'), diff --git a/core/client/routes/editor/edit.js b/core/client/routes/editor/edit.js index 324319a20f..e069aaa992 100644 --- a/core/client/routes/editor/edit.js +++ b/core/client/routes/editor/edit.js @@ -24,7 +24,8 @@ var EditorEditRoute = AuthenticatedRoute.extend(base, { return this.store.find('post', { id: params.post_id, status: 'all', - staticPages: 'all' + staticPages: 'all', + include: 'tags' }).then(function (records) { var post = records.get('firstObject'); @@ -43,11 +44,8 @@ var EditorEditRoute = AuthenticatedRoute.extend(base, { setupController: function (controller, model) { this._super(controller, model); controller.set('scratch', model.get('markdown')); - - model.get('tags').then(function (tags) { - // used to check if anything has changed in the editor - controller.set('previousTagNames', tags.mapBy('name')); - }); + // used to check if anything has changed in the editor + controller.set('previousTagNames', model.get('tags').mapBy('name')); }, actions: { diff --git a/core/client/routes/posts.js b/core/client/routes/posts.js index 0e1782dd43..9657ca702c 100644 --- a/core/client/routes/posts.js +++ b/core/client/routes/posts.js @@ -6,6 +6,7 @@ import loadingIndicator from 'ghost/mixins/loading-indicator'; var paginationSettings = { status: 'all', staticPages: 'all', + include: 'tags', page: 1 }; diff --git a/core/client/routes/posts/index.js b/core/client/routes/posts/index.js index 194977fe3d..4a01a81231 100644 --- a/core/client/routes/posts/index.js +++ b/core/client/routes/posts/index.js @@ -8,7 +8,8 @@ var PostsIndexRoute = AuthenticatedRoute.extend(loadingIndicator, { return this.store.find('post', { status: 'all', - staticPages: 'all' + staticPages: 'all', + include: 'tags' }).then(function (records) { var post = records.get('firstObject'); diff --git a/core/client/routes/posts/post.js b/core/client/routes/posts/post.js index 65340da987..32ed5cc5b0 100644 --- a/core/client/routes/posts/post.js +++ b/core/client/routes/posts/post.js @@ -23,7 +23,8 @@ var PostsPostRoute = AuthenticatedRoute.extend(loadingIndicator, ShortcutsRoute, return this.store.find('post', { id: params.post_id, status: 'all', - staticPages: 'all' + staticPages: 'all', + include: 'tags' }).then(function (records) { var post = records.get('firstObject'); diff --git a/core/client/serializers/post.js b/core/client/serializers/post.js index ff07e8a32e..1b252a17e3 100644 --- a/core/client/serializers/post.js +++ b/core/client/serializers/post.js @@ -1,16 +1,52 @@ import ApplicationSerializer from 'ghost/serializers/application'; -var PostSerializer = ApplicationSerializer.extend({ - serializeHasMany: function (record, json, relationship) { - var key = relationship.key; +var PostSerializer = ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, { + // settings for the EmbeddedRecordsMixin. + attrs: { + tags: { embedded: 'always' } + }, - if (key === 'tags') { - json[key] = Ember.get(record, key).map(function (tag) { - return tag.serialize({ includeId: true }); - }); - } else { - this._super.apply(this, arguments); + extractSingle: function (store, primaryType, payload) { + var root = this.keyForAttribute(primaryType.typeKey), + pluralizedRoot = Ember.String.pluralize(primaryType.typeKey); + + // make payload { post: { title: '', tags: [obj, obj], etc. } }. + // this allows ember-data to pull the embedded tags out again, + // in the function `updatePayloadWithEmbeddedHasMany` of the + // EmbeddedRecordsMixin (line: `if (!partial[attribute])`): + // https://github.com/emberjs/data/blob/master/packages/activemodel-adapter/lib/system/embedded_records_mixin.js#L499 + payload[root] = payload[pluralizedRoot][0]; + delete payload[pluralizedRoot]; + + return this._super.apply(this, arguments); + }, + + keyForAttribute: function (attr) { + return attr; + }, + + keyForRelationship: function (relationshipName) { + // this is a hack to prevent Ember-Data from deleting our `tags` reference. + // ref: https://github.com/emberjs/data/issues/2051 + // @TODO: remove this once the situation becomes clearer what to do. + if (relationshipName === 'tags') { + return 'tag'; } + + return relationshipName; + }, + + serializeIntoHash: function (hash, type, record, options) { + options = options || {}; + + // We have a plural root in the API + var root = Ember.String.pluralize(type.typeKey), + data = this.serialize(record, options); + + // Don't ever pass uuid's + delete data.uuid; + + hash[root] = [data]; } }); diff --git a/core/test/functional/base.js b/core/test/functional/base.js index a0a076f905..3f277c4e8b 100644 --- a/core/test/functional/base.js +++ b/core/test/functional/base.js @@ -524,10 +524,7 @@ CasperTest.Routines = (function () { casper.thenClick('.js-publish-button'); } - // **Note:** This should include tags on all post requests! Uncomment and replace lines below with this when fixed. - // casper.waitForResource(/posts\/\?include=tags$/); - - casper.waitForResource(/posts\/$/); + casper.waitForResource(/posts\/\?include=tags$/); } function _createRunner(fn) {