Skip to content

Commit

Permalink
Move buildURL and related methods to a mixin
Browse files Browse the repository at this point in the history
This is my first step towards emberjs/rfcs#4.

The intent here is to separate url building from the RESTAdapter so that
it can eventually be included in other adapters and hold the logic for the
path templating described in emberjs/rfcs#4.
  • Loading branch information
Amiel Martin committed Feb 21, 2015
1 parent 8d00fae commit 804e431
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 107 deletions.
111 changes: 111 additions & 0 deletions packages/ember-data/lib/adapters/build_url_mixin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
var get = Ember.get;

export default Ember.Mixin.create({
/**
Builds a URL for a given type and optional ID.
By default, it pluralizes the type's name (for example, 'post'
becomes 'posts' and 'person' becomes 'people'). To override the
pluralization see [pathForType](#method_pathForType).
If an ID is specified, it adds the ID to the path generated
for the type, separated by a `/`.
@method buildURL
@param {String} type
@param {String} id
@param {DS.Model} record
@return {String} url
*/
buildURL: function(type, id, record) {
var url = [];
var host = get(this, 'host');
var prefix = this.urlPrefix();

if (type) { url.push(this.pathForType(type)); }

//We might get passed in an array of ids from findMany
//in which case we don't want to modify the url, as the
//ids will be passed in through a query param
if (id && !Ember.isArray(id)) { url.push(encodeURIComponent(id)); }

if (prefix) { url.unshift(prefix); }

url = url.join('/');
if (!host && url) { url = '/' + url; }

return url;
},

/**
@method urlPrefix
@private
@param {String} path
@param {String} parentUrl
@return {String} urlPrefix
*/
urlPrefix: function(path, parentURL) {
var host = get(this, 'host');
var namespace = get(this, 'namespace');
var url = [];

if (path) {
// Protocol relative url
//jscs:disable disallowEmptyBlocks
if (/^\/\//.test(path)) {
// Do nothing, the full host is already included. This branch
// avoids the absolute path logic and the relative path logic.

// Absolute path
} else if (path.charAt(0) === '/') {
//jscs:enable disallowEmptyBlocks
if (host) {
path = path.slice(1);
url.push(host);
}
// Relative path
} else if (!/^http(s)?:\/\//.test(path)) {
url.push(parentURL);
}
} else {
if (host) { url.push(host); }
if (namespace) { url.push(namespace); }
}

if (path) {
url.push(path);
}

return url.join('/');
},


/**
Determines the pathname for a given type.
By default, it pluralizes the type's name (for example,
'post' becomes 'posts' and 'person' becomes 'people').
### Pathname customization
For example if you have an object LineItem with an
endpoint of "/line_items/".
```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
pathForType: function(type) {
var decamelized = Ember.String.decamelize(type);
return Ember.String.pluralize(decamelized);
}
});
```
@method pathForType
@param {String} type
@return {String} path
**/
pathForType: function(type) {
var camelized = Ember.String.camelize(type);
return Ember.String.pluralize(camelized);
}
});
110 changes: 3 additions & 107 deletions packages/ember-data/lib/adapters/rest_adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
var get = Ember.get;
var forEach = Ember.ArrayPolyfills.forEach;

import BuildURLMixin from "ember-data/adapters/build_url_mixin";

/**
The REST adapter allows your store to communicate with an HTTP server by
transmitting JSON via XHR. Most Ember.js apps that consume a JSON API
Expand Down Expand Up @@ -167,7 +169,7 @@ var forEach = Ember.ArrayPolyfills.forEach;
@namespace DS
@extends DS.Adapter
*/
export default Adapter.extend({
export default Adapter.extend(BuildURLMixin, {
defaultSerializer: '-rest',

/**
Expand Down Expand Up @@ -575,84 +577,6 @@ export default Adapter.extend({
return this.ajax(this.buildURL(type.typeKey, id, record), "DELETE");
},

/**
Builds a URL for a given type and optional ID.
By default, it pluralizes the type's name (for example, 'post'
becomes 'posts' and 'person' becomes 'people'). To override the
pluralization see [pathForType](#method_pathForType).
If an ID is specified, it adds the ID to the path generated
for the type, separated by a `/`.
@method buildURL
@param {String} type
@param {String} id
@param {DS.Model} record
@return {String} url
*/
buildURL: function(type, id, record) {
var url = [];
var host = get(this, 'host');
var prefix = this.urlPrefix();

if (type) { url.push(this.pathForType(type)); }

//We might get passed in an array of ids from findMany
//in which case we don't want to modify the url, as the
//ids will be passed in through a query param
if (id && !Ember.isArray(id)) { url.push(encodeURIComponent(id)); }

if (prefix) { url.unshift(prefix); }

url = url.join('/');
if (!host && url) { url = '/' + url; }

return url;
},

/**
@method urlPrefix
@private
@param {String} path
@param {String} parentUrl
@return {String} urlPrefix
*/
urlPrefix: function(path, parentURL) {
var host = get(this, 'host');
var namespace = get(this, 'namespace');
var url = [];

if (path) {
// Protocol relative url
//jscs:disable disallowEmptyBlocks
if (/^\/\//.test(path)) {
// Do nothing, the full host is already included. This branch
// avoids the absolute path logic and the relative path logic.

// Absolute path
} else if (path.charAt(0) === '/') {
//jscs:enable disallowEmptyBlocks
if (host) {
path = path.slice(1);
url.push(host);
}
// Relative path
} else if (!/^http(s)?:\/\//.test(path)) {
url.push(parentURL);
}
} else {
if (host) { url.push(host); }
if (namespace) { url.push(namespace); }
}

if (path) {
url.push(path);
}

return url.join('/');
},

_stripIDFromURL: function(store, record) {
var type = record.constructor;
var url = this.buildURL(type.typeKey, record.get('id'), record);
Expand Down Expand Up @@ -740,34 +664,6 @@ export default Adapter.extend({
return groupsArray;
},

/**
Determines the pathname for a given type.
By default, it pluralizes the type's name (for example,
'post' becomes 'posts' and 'person' becomes 'people').
### Pathname customization
For example if you have an object LineItem with an
endpoint of "/line_items/".
```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
pathForType: function(type) {
var decamelized = Ember.String.decamelize(type);
return Ember.String.pluralize(decamelized);
}
});
```
@method pathForType
@param {String} type
@return {String} path
**/
pathForType: function(type) {
var camelized = Ember.String.camelize(type);
return Ember.String.pluralize(camelized);
},

/**
Takes an ajax response, and returns an error payload.
Expand Down

0 comments on commit 804e431

Please sign in to comment.