Skip to content

Commit

Permalink
Merge pull request #2812 from amiel/move-buildUrl-to-mixin
Browse files Browse the repository at this point in the history
Move buildURL and related methods to a mixin
  • Loading branch information
fivetanley committed Mar 13, 2015
2 parents 2824af7 + 486f768 commit 6449e67
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 107 deletions.
138 changes: 138 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,138 @@
var get = Ember.get;

/**
WARNING: This interface is likely to change in order to accomodate https://github.com/emberjs/rfcs/pull/4
## Using BuildURLMixin
To use url building, include the mixin when extending an adapter, and call `buildURL` where needed.
The default behaviour is designed for RESTAdapter.
### Example
```javascript
export default DS.Adapter.extend(BuildURLMixin, {
find: function(store, type, id, record) {
var url = this.buildURL(type.typeKey, id, record);
return this.ajax(url, 'GET');
}
});
```
### Attributes
The `host` and `namespace` attributes will be used if defined, and are optional.
@class BuildURLMixin
@namespace DS
*/
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);
}
});
111 changes: 4 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 @@ -166,8 +168,9 @@ var forEach = Ember.ArrayPolyfills.forEach;
@constructor
@namespace DS
@extends DS.Adapter
@uses DS.BuildURLMixin
*/
export default Adapter.extend({
export default Adapter.extend(BuildURLMixin, {
defaultSerializer: '-rest',

/**
Expand Down Expand Up @@ -575,84 +578,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 +665,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
2 changes: 2 additions & 0 deletions packages/ember-data/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
RESTAdapter,
FixtureAdapter
} from "ember-data/adapters";
import BuildURLMixin from "ember-data/adapters/build_url_mixin";
import JSONSerializer from "ember-data/serializers/json_serializer";
import RESTSerializer from "ember-data/serializers/rest_serializer";
import "ember-inflector";
Expand Down Expand Up @@ -102,6 +103,7 @@ DS.ManyArray = ManyArray;
DS.RecordArrayManager = RecordArrayManager;

DS.RESTAdapter = RESTAdapter;
DS.BuildURLMixin = BuildURLMixin;
DS.FixtureAdapter = FixtureAdapter;

DS.RESTSerializer = RESTSerializer;
Expand Down

0 comments on commit 6449e67

Please sign in to comment.