angularjs-rails-resource 1.0.0.pre.3 → 1.0.0.pre.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -3
- data/README.md +98 -7
- data/bower.json +1 -1
- data/changelog.js +10 -1
- data/lib/angularjs-rails-resource/version.rb +1 -1
- data/package.json +1 -1
- data/test/unit/angularjs/rails/extensions/snapshotsSpec.js +0 -2
- data/test/unit/angularjs/rails/interceptorsSpec.js +413 -11
- data/test/unit/angularjs/rails/resourceSpec.js +19 -0
- data/test/unit/angularjs/rails/rootWrappingSpec.js +9 -24
- data/test/unit/angularjs/rails/transformersSpec.js +1 -2
- data/vendor/assets/javascripts/angularjs/rails/resource/extensions/snapshots.js +7 -4
- data/vendor/assets/javascripts/angularjs/rails/resource/resource.js +351 -115
- metadata +2 -2
@@ -478,6 +478,25 @@ describe('railsResourceFactory', function () {
|
|
478
478
|
$httpBackend.flush();
|
479
479
|
});
|
480
480
|
|
481
|
+
it('should not require query params on $delete', function () {
|
482
|
+
$httpBackend.expectDELETE('/test').respond(200);
|
483
|
+
Test.$delete('/test');
|
484
|
+
$httpBackend.flush();
|
485
|
+
});
|
486
|
+
|
487
|
+
it('should add query params passed to class $delete', function () {
|
488
|
+
$httpBackend.expectDELETE('/test?a=1').respond(200);
|
489
|
+
Test.$delete('/test', {a: 1});
|
490
|
+
$httpBackend.flush();
|
491
|
+
});
|
492
|
+
|
493
|
+
it('should add query params passed to instance $delete', function () {
|
494
|
+
var data = new Test({abcDef: 'xyz'});
|
495
|
+
|
496
|
+
$httpBackend.expectDELETE('/test?a=1').respond(200);
|
497
|
+
data.$delete('/test', {a: 1});
|
498
|
+
$httpBackend.flush();
|
499
|
+
});
|
481
500
|
});
|
482
501
|
|
483
502
|
describe('plural', function() {
|
@@ -3,33 +3,13 @@ describe('root wrapping', function () {
|
|
3
3
|
|
4
4
|
beforeEach(module('rails'));
|
5
5
|
|
6
|
-
var q, rootScope,
|
7
|
-
transformer, interceptor,
|
8
|
-
config = {config: {name: 'test', pluralName: 'tests'}};
|
6
|
+
var q, rootScope, railsRootWrapper, Resource;
|
9
7
|
|
10
|
-
|
11
|
-
function testTransform(wrappedData, unwrappedData) {
|
12
|
-
var result, resultPromise,
|
13
|
-
deferred = q.defer();
|
14
|
-
|
15
|
-
expect(transformer(unwrappedData, config)).toEqualData(wrappedData);
|
16
|
-
deferred.promise.resource = config;
|
17
|
-
expect(resultPromise = interceptor(deferred.promise)).toBeDefined();
|
18
|
-
|
19
|
-
resultPromise.then(function (response) {
|
20
|
-
result = response;
|
21
|
-
});
|
22
|
-
|
23
|
-
deferred.resolve({data: wrappedData});
|
24
|
-
rootScope.$digest(); // needed for $q to actually run callbacks
|
25
|
-
expect(result).toEqualData({data: unwrappedData});
|
26
|
-
}
|
27
|
-
|
28
|
-
beforeEach(inject(function ($rootScope, $q, railsRootWrappingTransformer, railsRootWrappingInterceptor) {
|
8
|
+
beforeEach(inject(function ($rootScope, $q, railsResourceFactory, _railsRootWrapper_) {
|
29
9
|
q = $q;
|
30
10
|
rootScope = $rootScope;
|
31
|
-
|
32
|
-
|
11
|
+
Resource = railsResourceFactory({name: 'test', pluralName: 'tests'});
|
12
|
+
railsRootWrapper = _railsRootWrapper_;
|
33
13
|
}));
|
34
14
|
|
35
15
|
it('should handle null root', function() {
|
@@ -43,4 +23,9 @@ describe('root wrapping', function () {
|
|
43
23
|
it('should transform object', function() {
|
44
24
|
testTransform({test: {abc: 'xyz', def: 'abc'}}, {abc: 'xyz', def: 'abc'});
|
45
25
|
});
|
26
|
+
|
27
|
+
function testTransform(wrappedData, unwrappedData) {
|
28
|
+
expect(railsRootWrapper.wrap(unwrappedData, Resource)).toEqualData(wrappedData);
|
29
|
+
expect(railsRootWrapper.unwrap({data: wrappedData}, Resource)).toEqualData({data: unwrappedData});
|
30
|
+
}
|
46
31
|
});
|
@@ -1,4 +1,4 @@
|
|
1
|
-
describe('transformers', function () {
|
1
|
+
describe('deprecated request transformers', function () {
|
2
2
|
'use strict';
|
3
3
|
var $httpBackend, $rootScope, factory, Test, testTransformer,
|
4
4
|
config = {
|
@@ -30,7 +30,6 @@ describe('transformers', function () {
|
|
30
30
|
$httpBackend.verifyNoOutstandingRequest();
|
31
31
|
});
|
32
32
|
|
33
|
-
|
34
33
|
it('should be able to add transformer using name', function() {
|
35
34
|
var Resource, testConfig = {};
|
36
35
|
|
@@ -8,9 +8,9 @@
|
|
8
8
|
};
|
9
9
|
|
10
10
|
RailsResourceSnapshotsMixin.extended = function (Resource) {
|
11
|
-
Resource.afterResponse
|
12
|
-
if (
|
13
|
-
|
11
|
+
Resource.intercept('afterResponse', function (result, resource, context) {
|
12
|
+
if (context && context.hasOwnProperty('$snapshots') && angular.isArray(context.$snapshots)) {
|
13
|
+
context.$snapshots.length = 0;
|
14
14
|
}
|
15
15
|
});
|
16
16
|
|
@@ -109,7 +109,10 @@
|
|
109
109
|
numVersions = snapshotsLength;
|
110
110
|
}
|
111
111
|
|
112
|
-
|
112
|
+
if (snapshotsLength) {
|
113
|
+
this.rollbackTo(this.$snapshots.length - numVersions);
|
114
|
+
}
|
115
|
+
|
113
116
|
return true;
|
114
117
|
}
|
115
118
|
|
@@ -1,21 +1,12 @@
|
|
1
1
|
(function (undefined) {
|
2
|
-
angular.module('rails').factory('
|
3
|
-
return
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
angular.module('rails').factory('railsRootWrappingInterceptor', function () {
|
11
|
-
return function (promise) {
|
12
|
-
var resource = promise.resource;
|
13
|
-
|
14
|
-
if (!resource) {
|
15
|
-
return promise;
|
16
|
-
}
|
17
|
-
|
18
|
-
return promise.then(function (response) {
|
2
|
+
angular.module('rails').factory('railsRootWrapper', function () {
|
3
|
+
return {
|
4
|
+
wrap: function (data, resource) {
|
5
|
+
var result = {};
|
6
|
+
result[angular.isArray(data) ? resource.config.pluralName : resource.config.name] = data;
|
7
|
+
return result;
|
8
|
+
},
|
9
|
+
unwrap: function (response, resource) {
|
19
10
|
if (response.data && response.data.hasOwnProperty(resource.config.name)) {
|
20
11
|
response.data = response.data[resource.config.name];
|
21
12
|
} else if (response.data && response.data.hasOwnProperty(resource.config.pluralName)) {
|
@@ -23,7 +14,7 @@
|
|
23
14
|
}
|
24
15
|
|
25
16
|
return response;
|
26
|
-
}
|
17
|
+
}
|
27
18
|
};
|
28
19
|
});
|
29
20
|
|
@@ -34,6 +25,7 @@
|
|
34
25
|
httpConfig: {},
|
35
26
|
defaultParams: undefined,
|
36
27
|
underscoreParams: true,
|
28
|
+
fullResponse: false,
|
37
29
|
extensions: []
|
38
30
|
};
|
39
31
|
|
@@ -91,6 +83,16 @@
|
|
91
83
|
return this;
|
92
84
|
};
|
93
85
|
|
86
|
+
/**
|
87
|
+
* Configures whether the full response from $http is returned or just the result data.
|
88
|
+
* @param {boolean} value true to return full $http response. Defaults to false.
|
89
|
+
* @returns {RailsResourceProvider} The provider instance
|
90
|
+
*/
|
91
|
+
this.fullResponse = function (value) {
|
92
|
+
defaultOptions.fullResponse = value;
|
93
|
+
return this;
|
94
|
+
};
|
95
|
+
|
94
96
|
/**
|
95
97
|
* List of RailsResource extensions to include by default.
|
96
98
|
*
|
@@ -105,28 +107,16 @@
|
|
105
107
|
return this;
|
106
108
|
};
|
107
109
|
|
108
|
-
this.$get = ['$http', '$q', 'railsUrlBuilder', 'railsSerializer', '
|
109
|
-
function ($http, $q, railsUrlBuilder, railsSerializer,
|
110
|
+
this.$get = ['$http', '$q', 'railsUrlBuilder', 'railsSerializer', 'railsRootWrapper', 'RailsResourceInjector',
|
111
|
+
function ($http, $q, railsUrlBuilder, railsSerializer, railsRootWrapper, RailsResourceInjector) {
|
110
112
|
|
111
113
|
function RailsResource(value) {
|
112
|
-
var instance = this;
|
113
|
-
this.$snapshots = [];
|
114
|
-
|
115
114
|
if (value) {
|
116
|
-
var
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
then: function (callback) {
|
122
|
-
this.response = callback(this.response, this.resource, this.context);
|
123
|
-
return immediatePromise(this.response);
|
124
|
-
}
|
125
|
-
};
|
126
|
-
};
|
127
|
-
|
128
|
-
var data = this.constructor.callInterceptors(immediatePromise({data: value}), this).response.data;
|
129
|
-
angular.extend(this, data);
|
115
|
+
var response = this.constructor.deserialize({data: value});
|
116
|
+
if (this.constructor.config.rootWrapping) {
|
117
|
+
response = railsRootWrapper.unwrap(response, this.constructor);
|
118
|
+
}
|
119
|
+
angular.extend(this, response.data);
|
130
120
|
}
|
131
121
|
}
|
132
122
|
|
@@ -226,10 +216,12 @@
|
|
226
216
|
this.config.defaultParams = cfg.defaultParams || defaultOptions.defaultParams;
|
227
217
|
this.config.underscoreParams = booleanParam(cfg.underscoreParams, defaultOptions.underscoreParams);
|
228
218
|
this.config.updateMethod = (cfg.updateMethod || defaultOptions.updateMethod).toLowerCase();
|
219
|
+
this.config.fullResponse = booleanParam(cfg.fullResponse, defaultOptions.fullResponse);
|
229
220
|
|
230
221
|
this.config.requestTransformers = cfg.requestTransformers ? cfg.requestTransformers.slice(0) : [];
|
231
222
|
this.config.responseInterceptors = cfg.responseInterceptors ? cfg.responseInterceptors.slice(0) : [];
|
232
223
|
this.config.afterResponseInterceptors = cfg.afterResponseInterceptors ? cfg.afterResponseInterceptors.slice(0) : [];
|
224
|
+
this.config.interceptors = cfg.interceptors ? cfg.interceptors.slice(0) : [];
|
233
225
|
|
234
226
|
this.config.serializer = RailsResourceInjector.getService(cfg.serializer || railsSerializer());
|
235
227
|
|
@@ -265,94 +257,241 @@
|
|
265
257
|
};
|
266
258
|
|
267
259
|
/**
|
268
|
-
*
|
260
|
+
* Interceptors utilize $q promises to allow for both synchronous and asynchronous processing during
|
261
|
+
* a request / response cycle.
|
262
|
+
*
|
263
|
+
* Interceptors can be added as a service factory name or as an object with properties matching one
|
264
|
+
* or more of the phases. Each property should have a value of a function to be called during that phase.
|
265
|
+
*
|
266
|
+
* There are multiple phases for both request and response. In addition, each phase has a corresponding
|
267
|
+
* error phase to handle promise rejections.
|
268
|
+
*
|
269
|
+
* Each request phase interceptor is called with the $http config object, the resource constructor, and if
|
270
|
+
* applicable the resource instance. The interceptor is free to modify the config or create a new one.
|
271
|
+
* The interceptor function must return a valid $http config or a promise that will eventually resolve
|
272
|
+
* to a config object.
|
273
|
+
*
|
274
|
+
* The valid request phases are:
|
275
|
+
*
|
276
|
+
* * beforeRequest: Interceptors are called prior to any data serialization or root wrapping.
|
277
|
+
* * beforeRequestError: Interceptors get called when a previous interceptor threw an error or
|
278
|
+
* resolved with a rejection.
|
279
|
+
* * beforeRequestWrapping: Interceptors are called after data serialization but before root wrapping.
|
280
|
+
* * beforeRequestWrappingError: Interceptors get called when a previous interceptor threw an error or
|
281
|
+
* resolved with a rejection.
|
282
|
+
* * request: Interceptors are called after any data serialization and root wrapping have been performed.
|
283
|
+
* * requestError: Interceptors get called when a previous interceptor threw an error or
|
284
|
+
* resolved with a rejection.
|
285
|
+
*
|
286
|
+
* The beforeResponse and response interceptors are called with the $http response object,
|
287
|
+
* the resource constructor, and if applicable the resource instance. The afterResponse interceptors
|
288
|
+
* are typically called with the response data instead of the full response object unless the config option
|
289
|
+
* fullResponse has been set to true. Like the request interceptor callbacks the response callbacks can
|
290
|
+
* manipulate the data or return new data. The interceptor function must return
|
291
|
+
*
|
292
|
+
* The valid response phases are:
|
293
|
+
*
|
294
|
+
* * beforeResponse: Interceptors are called prior to any data processing.
|
295
|
+
* * beforeResponseError: Interceptors get called when a previous interceptor threw an error or
|
296
|
+
* resolved with a rejection.
|
297
|
+
* * beforeResponseDeserialize: Interceptors are called after root unwrapping but prior to data deserializing.
|
298
|
+
* * beforeResponseDeserializeError: Interceptors get called when a previous interceptor threw an error or
|
299
|
+
* resolved with a rejection.
|
300
|
+
* * response: Interceptors are called after the data has been deserialized and root unwrapped but
|
301
|
+
* prior to the data being copied to the resource instance if applicable.
|
302
|
+
* * responseError: Interceptors get called when a previous interceptor threw an error or
|
303
|
+
* resolved with a rejection.
|
304
|
+
* * afterResponse: Interceptors are called at the very end of the response chain after all processing
|
305
|
+
* has been completed. The value of the first parameter is one of the following:
|
306
|
+
* - resource instance: When fullResponse is false and the operation was called on a resource instance.
|
307
|
+
* - response data: When fullResponse is false and the operation was called on the resource class.
|
308
|
+
* - $http response: When fullResponse is true
|
309
|
+
* * afterResponseError: Interceptors get called when a previous interceptor threw an error or
|
310
|
+
* resolved with a rejection.
|
311
|
+
*
|
312
|
+
* @param {String | Object} interceptor
|
313
|
+
*/
|
314
|
+
RailsResource.addInterceptor = function (interceptor) {
|
315
|
+
this.config.interceptors.push(interceptor);
|
316
|
+
};
|
317
|
+
|
318
|
+
/**
|
319
|
+
* Adds an interceptor callback function for the specified phase.
|
320
|
+
* @param {String} phase The interceptor phase, one of:
|
321
|
+
* beforeRequest, request, beforeResponse, response, afterResponse
|
322
|
+
* @param fn The function to call.
|
323
|
+
*/
|
324
|
+
RailsResource.intercept = function (phase, fn) {
|
325
|
+
var interceptor = {};
|
326
|
+
fn = RailsResourceInjector.getDependency(fn);
|
327
|
+
|
328
|
+
interceptor[phase] = function (value, resourceConstructor, context) {
|
329
|
+
return fn(value, resourceConstructor, context) || value;
|
330
|
+
};
|
331
|
+
|
332
|
+
this.addInterceptor(interceptor);
|
333
|
+
};
|
334
|
+
|
335
|
+
/**
|
336
|
+
* Adds interceptor on 'beforeRequest' phase.
|
337
|
+
* @param fn(httpConfig, constructor, context) - httpConfig is the config object to pass to $http,
|
338
|
+
* constructor is the resource class calling the function,
|
339
|
+
* context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
|
340
|
+
*/
|
341
|
+
RailsResource.interceptBeforeRequest = function (fn) {
|
342
|
+
this.intercept('beforeRequest', fn);
|
343
|
+
};
|
344
|
+
|
345
|
+
/**
|
346
|
+
* Adds interceptor on 'beforeRequestWrapping' phase.
|
347
|
+
* @param fn(httpConfig, constructor, context) - httpConfig is the config object to pass to $http,
|
348
|
+
* constructor is the resource class calling the function,
|
349
|
+
* context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
|
350
|
+
*/
|
351
|
+
RailsResource.interceptBeforeRequestWrapping = function (fn) {
|
352
|
+
this.intercept('beforeRequestWrapping', fn);
|
353
|
+
};
|
354
|
+
|
355
|
+
/**
|
356
|
+
* Adds interceptor on 'request' phase.
|
357
|
+
* @param fn(httpConfig, constructor, context) - httpConfig is the config object to pass to $http,
|
358
|
+
* constructor is the resource class calling the function,
|
359
|
+
* context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
|
360
|
+
*/
|
361
|
+
RailsResource.interceptRequest = function (fn) {
|
362
|
+
this.intercept('request', fn);
|
363
|
+
};
|
364
|
+
|
365
|
+
/**
|
366
|
+
* Adds interceptor on 'beforeResponse' phase.
|
367
|
+
* @param fn(response data, constructor, context) - response data is either the resource instance returned or an array of resource instances,
|
368
|
+
* constructor is the resource class calling the function,
|
369
|
+
* context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
|
370
|
+
*/
|
371
|
+
RailsResource.interceptBeforeResponse = function (fn) {
|
372
|
+
this.intercept('beforeResponse', fn);
|
373
|
+
};
|
374
|
+
|
375
|
+
/**
|
376
|
+
* Adds interceptor on 'beforeResponseDeserialize' phase.
|
377
|
+
* @param fn(response data, constructor, context) - response data is either the resource instance returned or an array of resource instances,
|
378
|
+
* constructor is the resource class calling the function,
|
379
|
+
* context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
|
380
|
+
*/
|
381
|
+
RailsResource.interceptBeforeResponseDeserialize = function (fn) {
|
382
|
+
this.intercept('beforeResponseDeserialize', fn);
|
383
|
+
};
|
384
|
+
|
385
|
+
/**
|
386
|
+
* Adds interceptor on 'response' phase.
|
387
|
+
* @param fn(response data, constructor, context) - response data is either the resource instance returned or an array of resource instances,
|
388
|
+
* constructor is the resource class calling the function,
|
389
|
+
* context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
|
390
|
+
*/
|
391
|
+
RailsResource.interceptResponse = function (fn) {
|
392
|
+
this.intercept('response', fn);
|
393
|
+
};
|
394
|
+
|
395
|
+
/**
|
396
|
+
* Adds interceptor on 'afterResponse' phase.
|
397
|
+
* @param fn(response data, constructor, context) - response data is either the resource instance returned or an array of resource instances,
|
398
|
+
* constructor is the resource class calling the function,
|
399
|
+
* context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
|
400
|
+
*/
|
401
|
+
RailsResource.interceptAfterResponse = function (fn) {
|
402
|
+
this.intercept('afterResponse', fn);
|
403
|
+
};
|
404
|
+
|
405
|
+
/**
|
406
|
+
* Deprecated, see interceptors
|
407
|
+
* Add a callback to run on response.
|
408
|
+
* @deprecated since version 1.0.0, use interceptResponse instead
|
269
409
|
* @param fn(response data, constructor, context) - response data is either the resource instance returned or an array of resource instances,
|
270
410
|
* constructor is the resource class calling the function,
|
271
411
|
* context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
|
272
412
|
*/
|
273
413
|
RailsResource.beforeResponse = function (fn) {
|
274
414
|
fn = RailsResourceInjector.getDependency(fn);
|
275
|
-
this.
|
276
|
-
|
277
|
-
|
278
|
-
return response;
|
279
|
-
});
|
415
|
+
this.interceptResponse(function (response, resource, context) {
|
416
|
+
fn(response.data, resource.config.resourceConstructor, context);
|
417
|
+
return response;
|
280
418
|
});
|
281
419
|
};
|
282
420
|
|
283
421
|
/**
|
422
|
+
* Deprecated, see interceptors
|
284
423
|
* Add a callback to run after response has been processed. These callbacks are not called on object construction.
|
424
|
+
* @deprecated since version 1.0.0, use interceptAfterResponse instead
|
285
425
|
* @param fn(response data, constructor) - response data is either the resource instance returned or an array of resource instances and constructor is the resource class calling the function
|
286
426
|
*/
|
287
427
|
RailsResource.afterResponse = function (fn) {
|
288
428
|
fn = RailsResourceInjector.getDependency(fn);
|
289
|
-
this.
|
290
|
-
|
291
|
-
|
292
|
-
return response;
|
293
|
-
});
|
429
|
+
this.interceptAfterResponse(function (response, resource, context) {
|
430
|
+
fn(response, resource.config.resourceConstructor, context);
|
431
|
+
return response;
|
294
432
|
});
|
295
433
|
};
|
296
434
|
|
297
435
|
/**
|
436
|
+
* Deprecated, see interceptors
|
298
437
|
* Adds a function to run after serializing the data to send to the server, but before root-wrapping it.
|
438
|
+
* @deprecated since version 1.0.0, use interceptBeforeRequestWrapping instead
|
299
439
|
* @param fn (data, constructor) - data object is the serialized resource instance, and constructor the resource class calling the function
|
300
440
|
*/
|
301
441
|
RailsResource.beforeRequest = function (fn) {
|
302
442
|
fn = RailsResourceInjector.getDependency(fn);
|
303
|
-
this.
|
304
|
-
|
443
|
+
this.interceptBeforeRequestWrapping(function (httpConfig, resource) {
|
444
|
+
httpConfig.data = fn(httpConfig.data, resource.config.resourceConstructor) || httpConfig.data;
|
445
|
+
return httpConfig;
|
305
446
|
});
|
306
447
|
};
|
307
448
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
data = config.serializer.serialize(data);
|
312
|
-
|
313
|
-
forEachDependency(this.config.requestTransformers, function (transformer) {
|
314
|
-
data = transformer(data, config.resourceConstructor);
|
315
|
-
});
|
316
|
-
|
317
|
-
if (config.rootWrapping) {
|
318
|
-
data = railsRootWrappingTransformer(data, config.resourceConstructor);
|
449
|
+
RailsResource.serialize = function (httpConfig) {
|
450
|
+
if (httpConfig.data) {
|
451
|
+
httpConfig.data = this.config.serializer.serialize(httpConfig.data);
|
319
452
|
}
|
320
453
|
|
321
|
-
return
|
454
|
+
return httpConfig;
|
322
455
|
};
|
323
456
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
promise = railsRootWrappingInterceptor(promise);
|
337
|
-
}
|
338
|
-
|
339
|
-
promise.then(function (response) {
|
340
|
-
response.data = config.serializer.deserialize(response.data, config.resourceConstructor);
|
341
|
-
return response;
|
342
|
-
});
|
457
|
+
/**
|
458
|
+
* Deserializes the response data on the $http response. Stores the original version of the data
|
459
|
+
* on the response as "originalData" and sets the deserialized data in the "data" property.
|
460
|
+
* @param response The $http response object
|
461
|
+
* @returns {*} The $http response
|
462
|
+
*/
|
463
|
+
RailsResource.deserialize = function (response) {
|
464
|
+
// store off the data so we don't lose access to it after deserializing and unwrapping
|
465
|
+
response.originalData = response.data;
|
466
|
+
response.data = this.config.serializer.deserialize(response.data, this.config.resourceConstructor);
|
467
|
+
return response;
|
468
|
+
};
|
343
469
|
|
344
|
-
|
470
|
+
/**
|
471
|
+
* Deprecated, see interceptors
|
472
|
+
* Transform data after response has been converted to a resource instance
|
473
|
+
* @deprecated
|
474
|
+
* @param promise
|
475
|
+
* @param context
|
476
|
+
*/
|
477
|
+
RailsResource.callResponseInterceptors = function (promise, context) {
|
478
|
+
var config = this.config;
|
345
479
|
forEachDependency(config.responseInterceptors, function (interceptor) {
|
346
480
|
promise.resource = config.resourceConstructor;
|
347
481
|
promise.context = context;
|
348
482
|
promise = interceptor(promise);
|
349
483
|
});
|
350
|
-
|
351
484
|
return promise;
|
352
485
|
};
|
353
486
|
|
354
|
-
|
355
|
-
|
487
|
+
/**
|
488
|
+
* Deprecated, see interceptors
|
489
|
+
* Transform data after response has been converted to a resource instance
|
490
|
+
* @deprecated
|
491
|
+
* @param promise
|
492
|
+
* @param context
|
493
|
+
*/
|
494
|
+
RailsResource.callAfterResponseInterceptors = function (promise) {
|
356
495
|
var config = this.config;
|
357
496
|
// data is now deserialized. call response interceptors including afterResponse
|
358
497
|
forEachDependency(config.afterResponseInterceptors, function (interceptor) {
|
@@ -363,12 +502,100 @@
|
|
363
502
|
return promise;
|
364
503
|
};
|
365
504
|
|
366
|
-
RailsResource.
|
367
|
-
|
368
|
-
|
505
|
+
RailsResource.runInterceptorPhase = function (phase, context, promise) {
|
506
|
+
var config = this.config, chain = [];
|
507
|
+
|
508
|
+
forEachDependency(config.interceptors, function (interceptor) {
|
509
|
+
if (interceptor[phase] || interceptor[phase + 'Error']) {
|
510
|
+
chain.push(interceptor[phase], interceptor[phase + 'Error']);
|
511
|
+
}
|
512
|
+
});
|
513
|
+
|
514
|
+
while (chain.length) {
|
515
|
+
var thenFn = chain.shift();
|
516
|
+
var rejectFn = chain.shift();
|
517
|
+
|
518
|
+
promise = promise.then(createInterceptorSuccessCallback(thenFn, config.resourceConstructor, context),
|
519
|
+
createInterceptorRejectionCallback(rejectFn, config.resourceConstructor, context));
|
520
|
+
}
|
521
|
+
|
522
|
+
return promise;
|
523
|
+
};
|
524
|
+
|
525
|
+
/**
|
526
|
+
* Executes an HTTP request using $http.
|
527
|
+
*
|
528
|
+
* This method is used by all RailsResource operations that execute HTTP requests. Handles serializing
|
529
|
+
* the request data using the resource serializer, root wrapping (if enabled), deserializing the response
|
530
|
+
* data using the resource serializer, root unwrapping (if enabled), and copying the result back into the
|
531
|
+
* resource context if applicable. Executes interceptors at each phase of the request / response to allow
|
532
|
+
* users to build synchronous & asynchronous customizations to manipulate the data as necessary.
|
533
|
+
*
|
534
|
+
* @param httpConfig The config to pass to $http, see $http docs for details
|
535
|
+
* @param context An optional reference to the resource instance that is the context for the operation.
|
536
|
+
* If specified, the result data will be copied into the context during the response handling.
|
537
|
+
* @param resourceConfigOverrides An optional set of RailsResource configuration options overrides.
|
538
|
+
* These overrides allow users to build custom operations more easily with different resource settings.
|
539
|
+
* @returns {Promise} The promise that will eventually be resolved after all request / response handling
|
540
|
+
* has completed.
|
541
|
+
*/
|
542
|
+
RailsResource.$http = function (httpConfig, context, resourceConfigOverrides) {
|
543
|
+
var config = angular.extend(angular.copy(this.config), resourceConfigOverrides || {}),
|
544
|
+
resourceConstructor = config.resourceConstructor,
|
545
|
+
promise = $q.when(httpConfig);
|
546
|
+
|
547
|
+
promise = this.runInterceptorPhase('beforeRequest', context, promise).then(function (httpConfig) {
|
548
|
+
httpConfig = resourceConstructor.serialize(httpConfig);
|
549
|
+
|
550
|
+
forEachDependency(config.requestTransformers, function (transformer) {
|
551
|
+
httpConfig.data = transformer(httpConfig.data, config.resourceConstructor);
|
552
|
+
});
|
553
|
+
|
554
|
+
return httpConfig;
|
369
555
|
});
|
370
556
|
|
371
|
-
|
557
|
+
promise = this.runInterceptorPhase('beforeRequestWrapping', context, promise);
|
558
|
+
|
559
|
+
if (config.rootWrapping) {
|
560
|
+
promise = promise.then(function (httpConfig) {
|
561
|
+
httpConfig.data = railsRootWrapper.wrap(httpConfig.data, config.resourceConstructor);
|
562
|
+
return httpConfig;
|
563
|
+
});
|
564
|
+
}
|
565
|
+
|
566
|
+
promise = this.runInterceptorPhase('request', context, promise).then(function (httpConfig) {
|
567
|
+
return $http(httpConfig);
|
568
|
+
});
|
569
|
+
|
570
|
+
promise = this.runInterceptorPhase('beforeResponse', context, promise);
|
571
|
+
|
572
|
+
if (config.rootWrapping) {
|
573
|
+
promise = promise.then(function (response) {
|
574
|
+
return railsRootWrapper.unwrap(response, config.resourceConstructor);
|
575
|
+
});
|
576
|
+
}
|
577
|
+
|
578
|
+
promise = this.runInterceptorPhase('beforeResponseDeserialize', context, promise).then(function (response) {
|
579
|
+
return resourceConstructor.deserialize(response);
|
580
|
+
});
|
581
|
+
|
582
|
+
promise = this.callResponseInterceptors(promise, context);
|
583
|
+
promise = this.runInterceptorPhase('response', context, promise).then(function (response) {
|
584
|
+
if (context) {
|
585
|
+
// we may not have response data
|
586
|
+
if (response.hasOwnProperty('data') && angular.isObject(response.data)) {
|
587
|
+
angular.extend(context, response.data);
|
588
|
+
}
|
589
|
+
}
|
590
|
+
|
591
|
+
return config.fullResponse ? response : (context || response.data);
|
592
|
+
});
|
593
|
+
|
594
|
+
promise = this.callAfterResponseInterceptors(promise, context);
|
595
|
+
promise = this.runInterceptorPhase('afterResponse', context, promise);
|
596
|
+
promise.resource = config.resourceConstructor;
|
597
|
+
promise.context = context;
|
598
|
+
return promise;
|
372
599
|
};
|
373
600
|
|
374
601
|
/**
|
@@ -442,7 +669,7 @@
|
|
442
669
|
};
|
443
670
|
|
444
671
|
RailsResource.$get = function (url, queryParams) {
|
445
|
-
return this.
|
672
|
+
return this.$http(angular.extend({method: 'get', url: url}, this.getHttpConfig(queryParams)));
|
446
673
|
};
|
447
674
|
|
448
675
|
RailsResource.query = function (queryParams, context) {
|
@@ -463,36 +690,32 @@
|
|
463
690
|
return appendPath(this.constructor.resourceUrl(this), path);
|
464
691
|
};
|
465
692
|
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
return this.constructor
|
693
|
+
/**
|
694
|
+
* Executes $http with the resource instance as the context.
|
695
|
+
*
|
696
|
+
* @param httpConfig The config to pass to $http, see $http docs for details
|
697
|
+
* @param context An optional reference to the resource instance that is the context for the operation.
|
698
|
+
* If specified, the result data will be copied into the context during the response handling.
|
699
|
+
* @param resourceConfigOverrides An optional set of RailsResource configuration options overrides.
|
700
|
+
* These overrides allow users to build custom operations more easily with different resource settings.
|
701
|
+
* @returns {Promise} The promise that will eventually be resolved after all request / response handling
|
702
|
+
* has completed.
|
703
|
+
*/
|
704
|
+
RailsResource.prototype.$http = function (httpConfig, resourceConfigOverrides) {
|
705
|
+
return this.constructor.$http(httpConfig, this, resourceConfigOvverides);
|
479
706
|
};
|
480
707
|
|
481
708
|
angular.forEach(['post', 'put', 'patch'], function (method) {
|
482
709
|
RailsResource['$' + method] = function (url, data) {
|
483
|
-
var config;
|
484
710
|
// clone so we can manipulate w/o modifying the actual instance
|
485
|
-
data =
|
486
|
-
|
487
|
-
return this.processResponse($http(config));
|
711
|
+
data = angular.copy(data);
|
712
|
+
return this.$http(angular.extend({method: method, url: url, data: data}, this.getHttpConfig()));
|
488
713
|
};
|
489
714
|
|
490
715
|
RailsResource.prototype['$' + method] = function (url) {
|
491
|
-
var data, config;
|
492
716
|
// clone so we can manipulate w/o modifying the actual instance
|
493
|
-
data =
|
494
|
-
|
495
|
-
return this.processResponse($http(config));
|
717
|
+
var data = angular.copy(this, {});
|
718
|
+
return this.constructor.$http(angular.extend({method: method, url: url, data: data}, this.constructor.getHttpConfig()), this);
|
496
719
|
|
497
720
|
};
|
498
721
|
});
|
@@ -518,12 +741,12 @@
|
|
518
741
|
}
|
519
742
|
};
|
520
743
|
|
521
|
-
RailsResource.$delete = function (url) {
|
522
|
-
return this.
|
744
|
+
RailsResource.$delete = function (url, queryParams) {
|
745
|
+
return this.$http(angular.extend({method: 'delete', url: url}, this.getHttpConfig(queryParams)));
|
523
746
|
};
|
524
747
|
|
525
|
-
RailsResource.prototype.$delete = function (url) {
|
526
|
-
return this.
|
748
|
+
RailsResource.prototype.$delete = function (url, queryParams) {
|
749
|
+
return this.constructor.$http(angular.extend({method: 'delete', url: url}, this.constructor.getHttpConfig(queryParams)), this);
|
527
750
|
};
|
528
751
|
|
529
752
|
//using ['delete'] instead of .delete for IE7/8 compatibility
|
@@ -600,6 +823,19 @@
|
|
600
823
|
function booleanParam(value, defaultValue) {
|
601
824
|
return angular.isUndefined(value) ? defaultValue : value;
|
602
825
|
}
|
826
|
+
|
827
|
+
function createInterceptorSuccessCallback(thenFn, resourceConstructor, context) {
|
828
|
+
return function (data) {
|
829
|
+
return (thenFn || angular.identity)(data, resourceConstructor, context);
|
830
|
+
};
|
831
|
+
}
|
832
|
+
|
833
|
+
function createInterceptorRejectionCallback(rejectFn, resourceConstructor, context) {
|
834
|
+
return function (rejection) {
|
835
|
+
// can't use identity because we need to return a rejected promise to keep the error chain going
|
836
|
+
return rejectFn ? rejectFn(rejection, resourceConstructor, context) : $q.reject(rejection);
|
837
|
+
};
|
838
|
+
}
|
603
839
|
}];
|
604
840
|
});
|
605
841
|
|