angularjs-rails-resource 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4bfbacbc10e68b92315a301e1419852f77b4c028
4
- data.tar.gz: 73c370919edead2bd08430a3551513196595389d
3
+ metadata.gz: 168a47c7cf77844625f4f730eb0a9f3c870618d7
4
+ data.tar.gz: ad71d9b538c88d7fb0c3ffb251ef94a44ebff3db
5
5
  SHA512:
6
- metadata.gz: 11b7134336f0441bdd6ee5cec43b5d683f82d1d1e965d55f50a174c69eca431ee7b927dc903bb43f57f1038fcd5fd75a54734ffb46cfa53c7a62bc27f8b30bc7
7
- data.tar.gz: 805dbd40dcc11ce20b3773c04fb974a5b2b2ae2c5f6a0e452a455c1c222da60f32ff3b8378413d5f12fe4dcaf530bb030beae592741e3889dce3a556b86b53f3
6
+ metadata.gz: b02702b23f89ddc927d956dde10aff6c5165dd0fff11da4258179384dede75429a172a3c56ed07495a8d4b24f2c60245dd37bb565500da3dda0c713ca66db4ba
7
+ data.tar.gz: 9bddfe4eaf76e420b5a7696e2120086218c2938d686802297889c0edc7cebd441f5b0eda161807c7f339b5b8020acd46f292dc667faa5cec4e5c136a02c0adf3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ <a name="1.2.0"></a>
2
+ # 1.2.0
3
+ ## Bug Fixes
4
+
5
+ ## Features
6
+ - Added <code>unsnappedChanges()</code> function to snapshots mixin to check whether or not there have been any changes since the last snapshot was taken. - #125 (@StevenClontz)
7
+ - Added <code>skipRequestProcessing</code> override configuration option to $http, $post, $put, $patch to bypass request processing (root wrapping, serialization) and request interceptor chains - #123 (@mayhewluke)
8
+
1
9
  <a name="1.1.0"></a>
2
10
  # 1.1.0
3
11
  ## Bug Fixes
data/EXAMPLES.md CHANGED
@@ -133,7 +133,7 @@ passes the resulting promise to the processResponse method which will perform th
133
133
  var resource = railsResourceFactory({url: '/books', name: 'book'});
134
134
  resource.prototype.getReferences = function () {
135
135
  var self = this;
136
- return resource.$get(self.$url('references'))).then(function (references) {
136
+ return resource.$get(self.$url('references')).then(function (references) {
137
137
  self.references = references;
138
138
  return self.references;
139
139
  });
@@ -142,7 +142,7 @@ passes the resulting promise to the processResponse method which will perform th
142
142
 
143
143
  # Specifying Transformer
144
144
  Transformers can be specified by an array of transformers in the configuration options passed to railsResourceFactory.
145
- However, a cleaner eway to write it is to use the <code>beforeRequest</code> which can take a new anonymous function or
145
+ However, a cleaner way to write it is to use the <code>beforeRequest</code> which can take a new anonymous function or
146
146
  a function returned by a factory if you want to share a transformer across multiple resources.
147
147
 
148
148
  Both of these examples can be accomplished using the serializers now.
data/README.md CHANGED
@@ -35,7 +35,7 @@ angular.module('app').config(["railsSerializerProvider", function(railsSerialize
35
35
  ### Rails Asset Pipeline
36
36
  Add this line to your application's Gemfile to use the latest stable version:
37
37
  ```ruby
38
- gem 'angularjs-rails-resource', '~> 1.0.0'
38
+ gem 'angularjs-rails-resource', '~> 1.1.1'
39
39
  ```
40
40
 
41
41
  Include the javascript somewhere in your asset pipeline:
@@ -298,9 +298,10 @@ RailsResources have the following class methods available.
298
298
  * **queryParams** {object} (optional) - The set of query parameters to include in the GET request
299
299
  * **returns** {promise} A promise that will be resolved with a new Resource instance (or instances in the case of an array response).
300
300
 
301
- * $post(customUrl, data), $put(customUrl, data), $patch(customUrl, data) - Serializes the data parameter using the Resource's normal serialization process and submits the result as a POST / PUT / PATCH to the given URL.
301
+ * $post/$put/$patch(customUrl, data, resourceConfigOverrides) - Serializes the data parameter using the Resource's normal serialization process and submits the result as a POST / PUT / PATCH to the given URL.
302
302
  * **customUrl** {string} - The url to POST / PUT / PATCH to
303
303
  * **data** {object} - The data to serialize and POST / PUT / PATCH
304
+ * **resourceConfigOverrides** {object} (optional) - An optional set of RailsResource configuration option overrides to use for this request. Root wrapping and serialization for the request data can be bypassed using the `skipRequestProcessing` flag. This also bypasses the entire pre-request [interceptor](#interceptors) chain.
304
305
  * **returns** {promise} A promise that will be resolved with a new Resource instance (or instances in the case of an array response).
305
306
 
306
307
  * $delete(customUrl, queryParams) - Executes a DELETE to a custom URL. The main difference between this and $http.delete is that a server response that contains a body will be deserialized using the normal Resource deserialization process.
@@ -311,7 +312,7 @@ RailsResources have the following class methods available.
311
312
  * $http(httpConfig, context, resourceConfigOverrides) - Executes an HTTP operation specified by the config. The request data is serialized and root wrapped (if configured). The response data is unwrapped (if configured) and deserialized and copied to the context object if specified.
312
313
  * **httpConfig** {object} - Standard $http config object.
313
314
  * **context** {object} - The instance that the operation is being run against.
314
- * **resourceConfigOverrides** {object} - An optional set of RailsResource configuration option overrides to use for this request.
315
+ * **resourceConfigOverrides** {object} (optional) - An optional set of RailsResource configuration option overrides to use for this request. Root wrapping and serialization for the request data can be bypassed using the `skipRequestProcessing` flag. This also bypasses the entire pre-request [interceptor](#interceptors) chain.
315
316
 
316
317
  * addInterceptor(interceptor) - Adds an interceptor to the resource class.
317
318
  * **interceptor** {object | string} - See [Interceptors](#interceptors) for details of object format.
@@ -327,7 +328,7 @@ RailsResources have the following class methods available.
327
328
  * interceptResponse - Shortcut for intercept('response', callback)
328
329
  * interceptAfterResponse - Shortcut for intercept('afterResponse', callback)
329
330
 
330
- **Deprecated**
331
+ **Deprecated**
331
332
  * beforeRequest(fn(data, resource)) - See [Interceptors](#interceptors) for more information. The function is called prior to the serialization process so the data
332
333
  passed to the function is still a Resource instance as long as another transformation function has not returned a new object to serialize.
333
334
  * fn(data, resource) {function} - The function to add as a transformer.
@@ -459,7 +460,7 @@ Interceptors are similar in design to the $http interceptors. You can add inter
459
460
 
460
461
  There are several phases for both request and response to give users and mixins more flexibility for exactly where they want to insert a customization. Each phase also has a corresponding error phase which is the phase name appended with Error (e.g. beforeResponse and beforeResponseError). The error phases receive the current rejection value which in most cases would be the error returned from $http. Since these are $q promises, your interceptor can decide whether or not to propagate the error or recover from it. If you want to propagate the error, you must return a <code>$q.reject(reason)</code> result. Otherwise any value you return will be treated as a successful value to use for the rest of the chain. For instance, in the <code>beforeResponseError</code> phase you could attempt to recover by using an alternate URL for the request data and return the new promise as the result.
461
462
 
462
- Each request phase interceptor is called with the $http config object, the resource constructor, and if applicable the resource instance. The interceptor is free to modify the config or create a new one. The interceptor function must return a valid $http config or a promise that will eventually resolve to a config object.
463
+ Each request phase interceptor is called with the $http config object, the resource constructor, and if applicable the resource instance. The interceptor is free to modify the config or create a new one. The interceptor function must return a valid $http config or a promise that will eventually resolve to a config object.
463
464
 
464
465
  The valid request phases are:
465
466
 
@@ -501,7 +502,7 @@ angular.module('rails').factory('saveIndicatorInterceptor', function () {
501
502
  if (context) {
502
503
  context.savePending = false;
503
504
  }
504
- return result;
505
+ return result;
505
506
  },
506
507
  'afterResponseError': function (rejection, resourceConstructor, context) {
507
508
  if (context) {
@@ -512,7 +513,7 @@ angular.module('rails').factory('saveIndicatorInterceptor', function () {
512
513
  };
513
514
  });
514
515
  ```
515
-
516
+
516
517
  ## Transformers / Interceptors (**DEPRECATED**)
517
518
  The transformers and interceptors can be specified using an array containing transformer/interceptor functions or strings
518
519
  that can be resolved using Angular's DI. The transformers / interceptors concept was prior to the [serializers](#serializers) but
@@ -671,6 +672,14 @@ snapshot version. <code>numVersions</code> can be used to roll back further tha
671
672
  * When <code>snapshotVersion</code> is less than 0 then the resource will be rolled back to the first version.
672
673
  * Otherwise, the resource will be rolled back to the specific version specified.
673
674
 
675
+ ##### unsnappedChanges
676
+ `unsnappedChanges()` checks to see if the resource has been changed since its last snapshot
677
+
678
+ * If there are no snapshots, returns `true`
679
+ * If all properties considered by `angular.equals` match the latest snapshot, returns `false`;
680
+ otherwise, returns `true`
681
+ * (Note that `angular.equals` [does not consider $-prefixed properties](https://docs.angularjs.org/api/ng/function/angular.equals))
682
+
674
683
  ## Tests
675
684
  The tests are written using [Jasmine](http://pivotal.github.com/jasmine/) and are run using [Karma](https://github.com/karma-runner/karma).
676
685
 
data/bower.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "angularjs-rails-resource",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "main": "angularjs-rails-resource.js",
5
5
  "description": "A resource factory inspired by $resource from AngularJS",
6
6
  "repository": {
@@ -1,7 +1,7 @@
1
1
  module Angularjs
2
2
  module Rails
3
3
  module Resource
4
- VERSION = '1.1.1'
4
+ VERSION = '1.2.0'
5
5
  end
6
6
  end
7
7
  end
data/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "angularjs-rails-resource",
3
3
  "description" : "A resource factory inspired by $resource from AngularJS",
4
- "version": "1.1.1",
4
+ "version": "1.2.0",
5
5
  "main" : "dist/angularjs-rails-resource.min.js",
6
6
  "homepage" : "https://github.com/FineLinePrototyping/angularjs-rails-resource.git",
7
7
  "author" : "",
@@ -348,6 +348,31 @@ describe('RailsResource.snapshots', function () {
348
348
  expect(secondCallbackCalled).toBe(true);
349
349
  });
350
350
 
351
+ it('should detect unsnapped changes', function () {
352
+ var book, data = {id: 1, $key: '1234', name: 'The Winds of Winter', theAuthor: 'George R.R. Martin'};
353
+ book = new Book(data);
354
+ expect(book.unsnappedChanges()).toBe(true);
355
+
356
+ book.snapshot();
357
+ expect(book.unsnappedChanges()).toBe(false);
358
+
359
+ book.name = 'Harry Potter';
360
+ expect(book.unsnappedChanges()).toBe(true);
361
+
362
+ book.snapshot();
363
+ expect(book.unsnappedChanges()).toBe(false);
364
+
365
+ book.theAuthor = 'J.K. Rowling';
366
+ expect(book.unsnappedChanges()).toBe(true);
367
+
368
+ book.snapshot();
369
+ expect(book.unsnappedChanges()).toBe(false);
370
+
371
+ // angular.equals ignores $-prefixed properties
372
+ book.$key = '1235'
373
+ expect(book.unsnappedChanges()).toBe(false);
374
+ });
375
+
351
376
  describe('serializer', function () {
352
377
  beforeEach(function () {
353
378
  Book.configure({
@@ -34,6 +34,92 @@ describe('http setting', function () {
34
34
  };
35
35
  }
36
36
 
37
+ describe('$post/$put/$patch', function() {
38
+
39
+ it('passes resourceConfigOverrides to $http', function() {
40
+ var methods = ['$post', '$put', '$patch'],
41
+ Resource = factory(config),
42
+ overrides = {baz: 'qux'};
43
+ spyOn(Resource, '$http');
44
+ angular.forEach(methods, function(method) {
45
+ Resource[method](null, null, overrides);
46
+ expect(Resource.$http.mostRecentCall.args[2]).toEqual(overrides);
47
+ });
48
+ expect(Resource.$http.calls.length).toBe(methods.length);
49
+ });
50
+
51
+ });
52
+
53
+ describe('$http', function() {
54
+
55
+ describe('when config includes skipRequestProcessing', function() {
56
+
57
+ it('skips all "before" interceptors', function() {
58
+ var phases = ['beforeRequest', 'beforeRequestWrapping', 'request'],
59
+ interceptors = {},
60
+ Resource = factory(config),
61
+ data = {foo: 'bar'},
62
+ httpConfig = {method: 'POST', url: config.url, data: data};
63
+
64
+ angular.forEach(phases, function(phase) {
65
+ interceptors[phase] = jasmine.createSpy(phase);
66
+ Resource.intercept(phase, interceptors[phase]);
67
+ });
68
+
69
+ $httpBackend.expectPOST(config.url, data).respond(200);
70
+ Resource.$http(httpConfig, null, {skipRequestProcessing: true});
71
+ $httpBackend.flush();
72
+
73
+ angular.forEach(phases, function(phase) {
74
+ expect(interceptors[phase]).not.toHaveBeenCalled();
75
+ });
76
+ });
77
+
78
+ it('does not skip "after" interceptors', function() {
79
+ var phases = ['beforeResponse', 'beforeResponseDeserialize', 'response', 'afterResponse'],
80
+ interceptors = {},
81
+ Resource = factory(config),
82
+ data = {foo: 'bar'},
83
+ httpConfig = {method: 'POST', url: config.url, data: data};
84
+
85
+ angular.forEach(phases, function(phase) {
86
+ interceptors[phase] = jasmine.createSpy(phase);
87
+ Resource.intercept(phase, interceptors[phase]);
88
+ });
89
+
90
+ $httpBackend.expectPOST(config.url, data).respond(200);
91
+ Resource.$http(httpConfig, null, {skipRequestProcessing: true});
92
+ $httpBackend.flush();
93
+
94
+ angular.forEach(phases, function(phase) {
95
+ expect(interceptors[phase]).toHaveBeenCalled();
96
+ });
97
+ });
98
+
99
+ it('deserializes the response into a Resource object', function() {
100
+
101
+ var promise,
102
+ result,
103
+ data = {foo: 'bar'},
104
+ httpConfig = {method: 'POST', url: config.url, data: data},
105
+ Resource = factory(config);
106
+
107
+ $httpBackend.expectPOST(config.url, data).respond(200, data);
108
+ promise = Resource.$http(httpConfig, null, {skipRequestProcessing: true});
109
+ promise.then(function(response) {
110
+ result = response;
111
+ });
112
+ $httpBackend.flush();
113
+
114
+ expect(result).toBeInstanceOf(Resource);
115
+ expect(result).toEqualData(data);
116
+
117
+ });
118
+
119
+ });
120
+
121
+ });
122
+
37
123
  it('query should pass default $http options', inject(function($httpBackend) {
38
124
  var promise, result, Test;
39
125
 
@@ -236,4 +322,4 @@ describe('http setting', function () {
236
322
  $httpBackend.flush();
237
323
  }));
238
324
 
239
- });
325
+ });
@@ -521,6 +521,36 @@ describe('railsResourceFactory', function () {
521
521
  data.$delete('/test', {a: 1});
522
522
  $httpBackend.flush();
523
523
  });
524
+
525
+ it('should return true for isNew when id undefined', function () {
526
+ expect(new Test().isNew()).toBeTruthy();
527
+ });
528
+
529
+ it('should return true for isNew when id is null', function () {
530
+ expect(new Test({id: null}).isNew()).toBeTruthy();
531
+ });
532
+
533
+ it('should return false for isNew when id is set', function () {
534
+ expect(new Test({id: 1}).isNew()).toBeFalsy();
535
+ });
536
+
537
+ describe('overridden idAttribute', function () {
538
+ beforeEach(inject(function (_$httpBackend_, _$rootScope_, railsResourceFactory) {
539
+ Test = railsResourceFactory({url: '/test', name: 'test', idAttribute: 'xyz'});
540
+ }));
541
+
542
+ it('should return true for isNew when xyz undefined', function () {
543
+ expect(new Test().isNew()).toBeTruthy();
544
+ });
545
+
546
+ it('should return true for isNew when xyz is null', function () {
547
+ expect(new Test({xyz: null}).isNew()).toBeTruthy();
548
+ });
549
+
550
+ it('should return false for isNew when xyz is set', function () {
551
+ expect(new Test({xyz: 1}).isNew()).toBeFalsy();
552
+ });
553
+ });
524
554
  });
525
555
 
526
556
  describe('plural', function() {
@@ -17,24 +17,37 @@
17
17
  Resource.include({
18
18
  snapshot: snapshot,
19
19
  rollback: rollback,
20
- rollbackTo: rollbackTo
20
+ rollbackTo: rollbackTo,
21
+ unsnappedChanges: unsnappedChanges,
22
+ _prepSnapshot: _prepSnapshot
21
23
  });
22
24
  };
23
25
 
24
26
  return RailsResourceSnapshotsMixin;
25
27
 
26
28
  /**
27
- * Stores a copy of this resource in the $snapshots array to allow undoing changes.
28
- * @param {function} rollbackCallback Optional callback function to be executed after the rollback.
29
- * @returns {Number} The version of the snapshot created (0-based index)
29
+ * Prepares a copy of the resource to be stored as a snapshot
30
+ * @returns {Resource} the copied resource, sans $snapshots
30
31
  */
31
- function snapshot(rollbackCallback) {
32
+ function _prepSnapshot() {
32
33
  var config = this.constructor.config,
33
34
  copy = (config.snapshotSerializer || config.serializer).serialize(this);
34
35
 
35
36
  // we don't want to store our snapshots in the snapshots because that would make the rollback kind of funny
36
37
  // not to mention using more memory for each snapshot.
37
38
  delete copy.$snapshots;
39
+
40
+ return copy
41
+ }
42
+
43
+ /**
44
+ * Stores a copy of this resource in the $snapshots array to allow undoing changes.
45
+ * @param {function} rollbackCallback Optional callback function to be executed after the rollback.
46
+ * @returns {Number} The version of the snapshot created (0-based index)
47
+ */
48
+ function snapshot(rollbackCallback) {
49
+ var copy = this._prepSnapshot();
50
+
38
51
  copy.$rollbackCallback = rollbackCallback;
39
52
 
40
53
  if (!this.$snapshots) {
@@ -116,5 +129,20 @@
116
129
  return true;
117
130
  }
118
131
 
132
+ /**
133
+ * Checks if resource is changed from the most recent snapshot.
134
+ * @returns {Boolean} true if the latest snapshot differs from resource as-is
135
+ */
136
+ function unsnappedChanges() {
137
+ if (!this.$snapshots) {
138
+ return true
139
+ }
140
+
141
+ var copy = this._prepSnapshot(),
142
+ latestSnap = this.$snapshots[this.$snapshots.length - 1]
143
+
144
+ return !angular.equals(copy, latestSnap)
145
+ }
146
+
119
147
  }]);
120
148
  }());
@@ -543,28 +543,36 @@
543
543
  resourceConstructor = config.resourceConstructor,
544
544
  promise = $q.when(httpConfig);
545
545
 
546
- promise = this.runInterceptorPhase('beforeRequest', context, promise).then(function (httpConfig) {
547
- httpConfig = resourceConstructor.serialize(httpConfig);
546
+ if (!config.skipRequestProcessing) {
548
547
 
549
- forEachDependency(config.requestTransformers, function (transformer) {
550
- httpConfig.data = transformer(httpConfig.data, config.resourceConstructor);
548
+ promise = this.runInterceptorPhase('beforeRequest', context, promise).then(function (httpConfig) {
549
+ httpConfig = resourceConstructor.serialize(httpConfig);
550
+
551
+ forEachDependency(config.requestTransformers, function (transformer) {
552
+ httpConfig.data = transformer(httpConfig.data, config.resourceConstructor);
553
+ });
554
+
555
+ return httpConfig;
551
556
  });
552
557
 
553
- return httpConfig;
554
- });
558
+ promise = this.runInterceptorPhase('beforeRequestWrapping', context, promise);
555
559
 
556
- promise = this.runInterceptorPhase('beforeRequestWrapping', context, promise);
560
+ if (config.rootWrapping) {
561
+ promise = promise.then(function (httpConfig) {
562
+ httpConfig.data = railsRootWrapper.wrap(httpConfig.data, config.resourceConstructor);
563
+ return httpConfig;
564
+ });
565
+ }
557
566
 
558
- if (config.rootWrapping) {
559
- promise = promise.then(function (httpConfig) {
560
- httpConfig.data = railsRootWrapper.wrap(httpConfig.data, config.resourceConstructor);
561
- return httpConfig;
567
+ promise = this.runInterceptorPhase('request', context, promise).then(function (httpConfig) {
568
+ return $http(httpConfig);
562
569
  });
563
- }
564
570
 
565
- promise = this.runInterceptorPhase('request', context, promise).then(function (httpConfig) {
566
- return $http(httpConfig);
567
- });
571
+ } else {
572
+
573
+ promise = $http(httpConfig);
574
+
575
+ }
568
576
 
569
577
  promise = this.runInterceptorPhase('beforeResponse', context, promise);
570
578
 
@@ -711,10 +719,10 @@
711
719
  };
712
720
 
713
721
  angular.forEach(['post', 'put', 'patch'], function (method) {
714
- RailsResource['$' + method] = function (url, data) {
722
+ RailsResource['$' + method] = function (url, data, resourceConfigOverrides) {
715
723
  // clone so we can manipulate w/o modifying the actual instance
716
724
  data = angular.copy(data);
717
- return this.$http(angular.extend({method: method, url: url, data: data}, this.getHttpConfig()));
725
+ return this.$http(angular.extend({method: method, url: url, data: data}, this.getHttpConfig()), null, resourceConfigOverrides);
718
726
  };
719
727
 
720
728
  RailsResource.prototype['$' + method] = function (url) {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: angularjs-rails-resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tommy Odom
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-12 00:00:00.000000000 Z
12
+ date: 2014-06-07 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A small AngularJS add-on for integrating with Rails via JSON more easily.
15
15
  email:
@@ -19,8 +19,8 @@ executables: []
19
19
  extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
- - .gitignore
23
- - .travis.yml
22
+ - ".gitignore"
23
+ - ".travis.yml"
24
24
  - CHANGELOG.md
25
25
  - EXAMPLES.md
26
26
  - Gemfile
@@ -71,17 +71,17 @@ require_paths:
71
71
  - lib
72
72
  required_ruby_version: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - '>='
74
+ - - ">="
75
75
  - !ruby/object:Gem::Version
76
76
  version: '0'
77
77
  required_rubygems_version: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - '>='
79
+ - - ">="
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
82
  requirements: []
83
83
  rubyforge_project:
84
- rubygems_version: 2.1.9
84
+ rubygems_version: 2.2.2
85
85
  signing_key:
86
86
  specification_version: 4
87
87
  summary: AngularJS add-on resource add-on for integrating with Rails