activeresource 5.1.1 → 6.0.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
  SHA256:
3
- metadata.gz: 9e0cde8f42f06f37aa13a7098b9a1e828aac34c90971a62f4c9a1a7fcf529ce7
4
- data.tar.gz: 11e7f85a7c565de83cb5248d8ee35783b343b8714e8ed9adcf08462f8aaceeda
3
+ metadata.gz: f2a0c925e2619c4a4204eebdaea70776a57fec944e9eefeb98982ed8cf425bbc
4
+ data.tar.gz: b77c66a74c3fe0d32e16d0ce4eaaec1c772200bda9ea36b2bfba1a3cc4f58b5d
5
5
  SHA512:
6
- metadata.gz: 133f4a82c31d9c925bc1c04a304c63e03982d45aa51b97d7e9ba580a433579802fb811a32009d40ebb7fc84e947fe65c60fd658b2cebb2f2f4c724efc536f528
7
- data.tar.gz: 0f0042b3b644fe8584d34403913f2e11363a684fe438d536303871baaed2a98f26319b0e1dcd036364b42597b48e76c5713a627ea4431a2b2ec9263fce98b3a6
6
+ metadata.gz: 9116078833a262f5a4d184a9cd080f3a29bfc5c07481cf352dd87baa735ba0dfae6159a35ac37ea1ad2e121348a33d958151a048af8dbb6e85e3a387076de3b5
7
+ data.tar.gz: 02e8b7e3aa1fd89f70f67b2696d778bf0c4a5d89c4b6f779ec3ecffc6a099374c06515ec2bfcb4e7175a518f00543f16b1b691670378c2533fcf353ce82cb96f
data/README.md ADDED
@@ -0,0 +1,324 @@
1
+ # Active Resource
2
+
3
+ Active Resource (ARes) connects business objects and Representational State Transfer (REST)
4
+ web services. It implements object-relational mapping for REST web services to provide transparent
5
+ proxying capabilities between a client (Active Resource) and a RESTful service (which is provided by
6
+ Simply RESTful routing in `ActionController::Resources`).
7
+
8
+ ## Philosophy
9
+
10
+ Active Resource attempts to provide a coherent wrapper object-relational mapping for REST
11
+ web services. It follows the same philosophy as Active Record, in that one of its prime aims
12
+ is to reduce the amount of code needed to map to these resources. This is made possible
13
+ by relying on a number of code- and protocol-based conventions that make it easy for Active Resource
14
+ to infer complex relations and structures. These conventions are outlined in detail in the documentation
15
+ for `ActiveResource::Base`.
16
+
17
+ ## Overview
18
+
19
+ Model classes are mapped to remote REST resources by Active Resource much the same way Active Record maps
20
+ model classes to database tables. When a request is made to a remote resource, a REST JSON request is
21
+ generated, transmitted, and the result received and serialized into a usable Ruby object.
22
+
23
+ ## Download and installation
24
+
25
+ The latest version of Active Resource can be installed with RubyGems:
26
+
27
+ ```
28
+ gem install activeresource
29
+ ```
30
+
31
+ Or added to a Gemfile:
32
+
33
+ ```ruby
34
+ gem 'activeresource'
35
+ ```
36
+
37
+ Source code can be downloaded on GitHub
38
+
39
+ * https://github.com/rails/activeresource/tree/main
40
+
41
+ ### Configuration and Usage
42
+
43
+ Putting Active Resource to use is very similar to Active Record. It's as simple as creating a model class
44
+ that inherits from `ActiveResource::Base` and providing a `site` class variable to it:
45
+
46
+ ```ruby
47
+ class Person < ActiveResource::Base
48
+ self.site = "http://api.people.com:3000"
49
+ end
50
+ ```
51
+
52
+ Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes
53
+ life cycle methods that operate against a persistent store.
54
+
55
+ ```ruby
56
+ # Find a person with id = 1
57
+ tyler = Person.find(1)
58
+ Person.exists?(1) # => true
59
+ ```
60
+
61
+ As you can see, the methods are quite similar to Active Record's methods for dealing with database
62
+ records. But rather than dealing directly with a database record, you're dealing with HTTP resources
63
+ (which may or may not be database records).
64
+
65
+ Connection settings (`site`, `headers`, `user`, `password`, `bearer_token`, `proxy`) and the connections
66
+ themselves are store in thread-local variables to make them thread-safe, so you can also set these
67
+ dynamically, even in a multi-threaded environment, for instance:
68
+
69
+ ```ruby
70
+ ActiveResource::Base.site = api_site_for(request)
71
+ ```
72
+ ### Authentication
73
+
74
+ Active Resource supports the token based authentication provided by Rails through the
75
+ `ActionController::HttpAuthentication::Token` class using custom headers.
76
+
77
+ ```ruby
78
+ class Person < ActiveResource::Base
79
+ self.headers['Authorization'] = 'Token token="abcd"'
80
+ end
81
+ ```
82
+
83
+ You can also set any specific HTTP header using the same way. As mentioned above, headers are
84
+ thread-safe, so you can set headers dynamically, even in a multi-threaded environment:
85
+
86
+ ```ruby
87
+ ActiveResource::Base.headers['Authorization'] = current_session_api_token
88
+ ```
89
+
90
+ Active Resource supports 2 options for HTTP authentication today.
91
+
92
+ 1. Basic
93
+ ```ruby
94
+ class Person < ActiveResource::Base
95
+ self.user = 'my@email.com'
96
+ self.password = '123'
97
+ end
98
+ # username: my@email.com password: 123
99
+ ```
100
+
101
+ 2. Bearer Token
102
+ ```ruby
103
+ class Person < ActiveResource::Base
104
+ self.auth_type = :bearer
105
+ self.bearer_token = 'my-token123'
106
+ end
107
+ # Bearer my-token123
108
+ ```
109
+
110
+ ### Protocol
111
+
112
+ Active Resource is built on a standard JSON or XML format for requesting and submitting resources
113
+ over HTTP. It mirrors the RESTful routing built into Action Controller but will also work with any
114
+ other REST service that properly implements the protocol. REST uses HTTP, but unlike "typical" web
115
+ applications, it makes use of all the verubys available in the HTTP specification:
116
+
117
+ * GET requests are used for finding and retrieving resources.
118
+ * POST requests are used to create new resources.
119
+ * PUT requests are used to update existing resources.
120
+ * DELETE requests are used to delete resources.
121
+
122
+ For more information on how this protocol works with Active Resource, see the `ActiveResource::Base` documentation;
123
+ for more general information on REST web services, see the article
124
+ [here](http://en.wikipedia.org/wiki/Representational_State_Transfer).
125
+
126
+ ### Find
127
+
128
+ Find requests use the GET method and expect the JSON form of whatever resource/resources is/are
129
+ being requested. So, for a request for a single element, the JSON of that item is expected in
130
+ response:
131
+
132
+ ```ruby
133
+ # Expects a response of
134
+ #
135
+ # {"id":1,"first":"Tyler","last":"Durden"}
136
+ #
137
+ # for GET http://api.people.com:3000/people/1.json
138
+ #
139
+ tyler = Person.find(1)
140
+ ```
141
+
142
+ The JSON document that is received is used to build a new object of type Person, with each
143
+ JSON element becoming an attribute on the object.
144
+
145
+ ```ruby
146
+ tyler.is_a? Person # => true
147
+ tyler.last # => 'Durden'
148
+ ```
149
+
150
+ Any complex element (one that contains other elements) becomes its own object:
151
+
152
+ ```ruby
153
+ # With this response:
154
+ # {"id":1,"first":"Tyler","address":{"street":"Paper St.","state":"CA"}}
155
+ #
156
+ # for GET http://api.people.com:3000/people/1.json
157
+ #
158
+ tyler = Person.find(1)
159
+ tyler.address # => <Person::Address::xxxxx>
160
+ tyler.address.street # => 'Paper St.'
161
+ ```
162
+
163
+ Collections can also be requested in a similar fashion
164
+
165
+ ```ruby
166
+ # Expects a response of
167
+ #
168
+ # [
169
+ # {"id":1,"first":"Tyler","last":"Durden"},
170
+ # {"id":2,"first":"Tony","last":"Stark",}
171
+ # ]
172
+ #
173
+ # for GET http://api.people.com:3000/people.json
174
+ #
175
+ people = Person.all
176
+ people.first # => <Person::xxx 'first' => 'Tyler' ...>
177
+ people.last # => <Person::xxx 'first' => 'Tony' ...>
178
+ ```
179
+
180
+ ### Create
181
+
182
+ Creating a new resource submits the JSON form of the resource as the body of the request and expects
183
+ a 'Location' header in the response with the RESTful URL location of the newly created resource. The
184
+ id of the newly created resource is parsed out of the Location response header and automatically set
185
+ as the id of the ARes object.
186
+
187
+ ```ruby
188
+ # {"first":"Tyler","last":"Durden"}
189
+ #
190
+ # is submitted as the body on
191
+ #
192
+ # if include_root_in_json is not set or set to false => {"first":"Tyler"}
193
+ # if include_root_in_json is set to true => {"person":{"first":"Tyler"}}
194
+ #
195
+ # POST http://api.people.com:3000/people.json
196
+ #
197
+ # when save is called on a new Person object. An empty response is
198
+ # is expected with a 'Location' header value:
199
+ #
200
+ # Response (201): Location: http://api.people.com:3000/people/2
201
+ #
202
+ tyler = Person.new(:first => 'Tyler')
203
+ tyler.new? # => true
204
+ tyler.save # => true
205
+ tyler.new? # => false
206
+ tyler.id # => 2
207
+ ```
208
+
209
+ ### Update
210
+
211
+ 'save' is also used to update an existing resource and follows the same protocol as creating a resource
212
+ with the exception that no response headers are needed -- just an empty response when the update on the
213
+ server side was successful.
214
+
215
+ ```ruby
216
+ # {"first":"Tyler"}
217
+ #
218
+ # is submitted as the body on
219
+ #
220
+ # if include_root_in_json is not set or set to false => {"first":"Tyler"}
221
+ # if include_root_in_json is set to true => {"person":{"first":"Tyler"}}
222
+ #
223
+ # PUT http://api.people.com:3000/people/1.json
224
+ #
225
+ # when save is called on an existing Person object. An empty response is
226
+ # is expected with code (204)
227
+ #
228
+ tyler = Person.find(1)
229
+ tyler.first # => 'Tyler'
230
+ tyler.first = 'Tyson'
231
+ tyler.save # => true
232
+ ```
233
+
234
+ ### Delete
235
+
236
+ Destruction of a resource can be invoked as a class and instance method of the resource.
237
+
238
+ ```ruby
239
+ # A request is made to
240
+ #
241
+ # DELETE http://api.people.com:3000/people/1.json
242
+ #
243
+ # for both of these forms. An empty response with
244
+ # is expected with response code (200)
245
+ #
246
+ tyler = Person.find(1)
247
+ tyler.destroy # => true
248
+ tyler.exists? # => false
249
+ Person.delete(2) # => true
250
+ Person.exists?(2) # => false
251
+ ```
252
+
253
+ ### Associations
254
+
255
+ Relationships between resources can be declared using the standard association syntax
256
+ that should be familiar to anyone who uses Active Record. For example, using the
257
+ class definition below:
258
+
259
+ ```ruby
260
+ class Post < ActiveResource::Base
261
+ self.site = "http://blog.io"
262
+ has_many :comments
263
+ end
264
+
265
+ post = Post.find(1) # issues GET http://blog.io/posts/1.json
266
+ comments = post.comments # issues GET http://blog.io/comments.json?post_id=1
267
+ ```
268
+
269
+ In this case, the `Comment` model would have to be implemented as Active Resource, too.
270
+
271
+ If you control the server, you may wish to include nested resources thus avoiding a
272
+ second network request. Given the resource above, if the response includes comments
273
+ in the response, they will be automatically loaded into the Active Resource object.
274
+ The server-side model can be adjusted as follows to include comments in the response.
275
+
276
+ ```ruby
277
+ class Post < ActiveRecord::Base
278
+ has_many :comments
279
+
280
+ def as_json(options)
281
+ super.merge(:include=>[:comments])
282
+ end
283
+ end
284
+ ```
285
+
286
+ ### Logging
287
+
288
+ Active Resource instruments the event `request.active_resource` when doing a request
289
+ to the remote service. You can subscribe to it by doing:
290
+
291
+ ```ruby
292
+ ActiveSupport::Notifications.subscribe('request.active_resource') do |name, start, finish, id, payload|
293
+ ```
294
+
295
+ The `payload` is a `Hash` with the following keys:
296
+
297
+ * `method` as a `Symbol`
298
+ * `request_uri` as a `String`
299
+ * `result` as an `Net::HTTPResponse`
300
+
301
+ ## License
302
+
303
+ Active Resource is released under the MIT license:
304
+
305
+ * http://www.opensource.org/licenses/MIT
306
+
307
+ ## Contributing to Active Resource
308
+
309
+ Active Resource is work of many contributors. You're encouraged to submit pull requests, propose
310
+ features and discuss issues.
311
+
312
+ See [CONTRIBUTING](https://github.com/rails/activeresource/blob/main/CONTRIBUTING.md).
313
+
314
+ ## Support
315
+
316
+ Full API documentation is available at
317
+
318
+ * http://rubydoc.info/gems/activeresource
319
+
320
+ Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
321
+
322
+ * https://github.com/rails/activeresource/issues
323
+
324
+ You can find more usage information in the ActiveResource::Base documentation.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveResource::Associations::Builder
4
- class Association #:nodoc:
4
+ class Association # :nodoc:
5
5
  # providing a Class-Variable, which will have a different store of subclasses
6
6
  class_attribute :valid_options
7
7
  self.valid_options = [:class_name]
@@ -25,7 +25,6 @@ module ActiveResource::Associations::Builder
25
25
  end
26
26
 
27
27
  private
28
-
29
28
  def validate_options
30
29
  options.assert_valid_keys(self.class.valid_options)
31
30
  end
@@ -148,7 +148,7 @@ module ActiveResource::Associations
148
148
  elsif attributes.include?(method_name)
149
149
  attributes[method_name]
150
150
  elsif !new_record?
151
- instance_variable_set(ivar_name, reflection.klass.find(:all, params: { :"#{self.class.element_name}_id" => self.id }))
151
+ instance_variable_set(ivar_name, reflection.klass.find(:all, params: { "#{self.class.element_name}_id": self.id }))
152
152
  else
153
153
  instance_variable_set(ivar_name, self.class.collection_parser.new)
154
154
  end
@@ -166,7 +166,7 @@ module ActiveResource::Associations
166
166
  elsif attributes.include?(method_name)
167
167
  attributes[method_name]
168
168
  elsif reflection.klass.respond_to?(:singleton_name)
169
- instance_variable_set(ivar_name, reflection.klass.find(params: { :"#{self.class.element_name}_id" => self.id }))
169
+ instance_variable_set(ivar_name, reflection.klass.find(params: { "#{self.class.element_name}_id": self.id }))
170
170
  else
171
171
  instance_variable_set(ivar_name, reflection.klass.find(:one, from: "/#{self.class.collection_name}/#{self.id}/#{method_name}#{self.class.format_extension}"))
172
172
  end
@@ -13,7 +13,6 @@ require "active_support/core_ext/object/duplicable"
13
13
  require "set"
14
14
  require "uri"
15
15
 
16
- require "active_support/core_ext/uri"
17
16
  require "active_resource/connection"
18
17
  require "active_resource/formats"
19
18
  require "active_resource/schema"
@@ -127,18 +126,25 @@ module ActiveResource
127
126
  # requests. These sensitive credentials are sent unencrypted, visible to
128
127
  # any onlooker, so this scheme should only be used with SSL.
129
128
  #
130
- # Digest authentication sends a crytographic hash of the username, password,
129
+ # Digest authentication sends a cryptographic hash of the username, password,
131
130
  # HTTP method, URI, and a single-use secret key provided by the server.
132
131
  # Sensitive credentials aren't visible to onlookers, so digest authentication
133
132
  # doesn't require SSL. However, this doesn't mean the connection is secure!
134
133
  # Just the username and password.
135
134
  #
135
+ # Another common way to authenticate requests is via bearer tokens, a scheme
136
+ # originally created as part of the OAuth 2.0 protocol (see RFC 6750).
137
+ #
138
+ # Bearer authentication sends a token, that can maybe only be a short string
139
+ # of hexadecimal characters or even a JWT Token. Similarly to the Basic
140
+ # authentication, this scheme should only be used with SSL.
141
+ #
136
142
  # (You really, really want to use SSL. There's little reason not to.)
137
143
  #
138
144
  # === Picking an authentication scheme
139
145
  #
140
- # Basic authentication is the default. To switch to digest authentication,
141
- # set +auth_type+ to +:digest+:
146
+ # Basic authentication is the default. To switch to digest or bearer token authentication,
147
+ # set +auth_type+ to +:digest+ or +:bearer+:
142
148
  #
143
149
  # class Person < ActiveResource::Base
144
150
  # self.auth_type = :digest
@@ -157,6 +163,16 @@ module ActiveResource
157
163
  # self.site = "https://ryan:password@api.people.com"
158
164
  # end
159
165
  #
166
+ # === Setting the bearer token
167
+ #
168
+ # Set +bearer_token+ on the class:
169
+ #
170
+ # class Person < ActiveResource::Base
171
+ # # Set bearer token directly:
172
+ # self.auth_type = :bearer
173
+ # self.bearer_token = "my-bearer-token"
174
+ # end
175
+ #
160
176
  # === Certificate Authentication
161
177
  #
162
178
  # You can also authenticate using an X509 certificate. <tt>See ssl_options=</tt> for all options.
@@ -202,7 +218,9 @@ module ActiveResource
202
218
  # * 405 - ActiveResource::MethodNotAllowed
203
219
  # * 409 - ActiveResource::ResourceConflict
204
220
  # * 410 - ActiveResource::ResourceGone
221
+ # * 412 - ActiveResource::PreconditionFailed
205
222
  # * 422 - ActiveResource::ResourceInvalid (rescued by save as validation errors)
223
+ # * 429 - ActiveResource::TooManyRequests
206
224
  # * 401..499 - ActiveResource::ClientError
207
225
  # * 500..599 - ActiveResource::ServerError
208
226
  # * Other - ActiveResource::ConnectionError
@@ -319,7 +337,7 @@ module ActiveResource
319
337
 
320
338
  class << self
321
339
  include ThreadsafeAttributes
322
- threadsafe_attribute :_headers, :_connection, :_user, :_password, :_site, :_proxy
340
+ threadsafe_attribute :_headers, :_connection, :_user, :_password, :_bearer_token, :_site, :_proxy
323
341
 
324
342
  # Creates a schema for this resource - setting the attributes that are
325
343
  # known prior to fetching an instance from the remote system.
@@ -407,7 +425,7 @@ module ActiveResource
407
425
  # example:
408
426
  #
409
427
  # class Person < ActiveResource::Base
410
- # schema = {'name' => :string, 'age' => :integer }
428
+ # self.schema = {'name' => :string, 'age' => :integer }
411
429
  # end
412
430
  #
413
431
  # The keys/values can be strings or symbols. They will be converted to
@@ -472,8 +490,8 @@ module ActiveResource
472
490
  self._site = nil
473
491
  else
474
492
  self._site = create_site_uri_from(site)
475
- self._user = URI.parser.unescape(_site.user) if _site.user
476
- self._password = URI.parser.unescape(_site.password) if _site.password
493
+ self._user = URI::DEFAULT_PARSER.unescape(_site.user) if _site.user
494
+ self._password = URI::DEFAULT_PARSER.unescape(_site.password) if _site.password
477
495
  end
478
496
  end
479
497
 
@@ -525,6 +543,22 @@ module ActiveResource
525
543
  self._password = password
526
544
  end
527
545
 
546
+ # Gets the \bearer_token for REST HTTP authentication.
547
+ def bearer_token
548
+ # Not using superclass_delegating_reader. See +site+ for explanation
549
+ if _bearer_token_defined?
550
+ _bearer_token
551
+ elsif superclass != Object && superclass.bearer_token
552
+ superclass.bearer_token.dup.freeze
553
+ end
554
+ end
555
+
556
+ # Sets the \bearer_token for REST HTTP authentication.
557
+ def bearer_token=(bearer_token)
558
+ self._connection = nil
559
+ self._bearer_token = bearer_token
560
+ end
561
+
528
562
  def auth_type
529
563
  if defined?(@auth_type)
530
564
  @auth_type
@@ -649,6 +683,7 @@ module ActiveResource
649
683
  _connection.proxy = proxy if proxy
650
684
  _connection.user = user if user
651
685
  _connection.password = password if password
686
+ _connection.bearer_token = bearer_token if bearer_token
652
687
  _connection.auth_type = auth_type if auth_type
653
688
  _connection.timeout = timeout if timeout
654
689
  _connection.open_timeout = open_timeout if open_timeout
@@ -661,11 +696,10 @@ module ActiveResource
661
696
  end
662
697
 
663
698
  def headers
664
- headers_state = self._headers || {}
665
- if superclass != Object
666
- self._headers = superclass.headers.merge(headers_state)
699
+ self._headers ||= if superclass != Object
700
+ InheritingHash.new(superclass.headers)
667
701
  else
668
- headers_state
702
+ {}
669
703
  end
670
704
  end
671
705
 
@@ -716,7 +750,7 @@ module ActiveResource
716
750
  # Default value is <tt>site.path</tt>.
717
751
  def prefix=(value = "/")
718
752
  # Replace :placeholders with '#{embedded options[:lookups]}'
719
- prefix_call = value.gsub(/:\w+/) { |key| "\#{URI.parser.escape options[#{key}].to_s}" }
753
+ prefix_call = value.gsub(/:\w+/) { |key| "\#{URI::DEFAULT_PARSER.escape options[#{key}].to_s}" }
720
754
 
721
755
  # Clear prefix parameters in case they have been cached
722
756
  @prefix_parameters = nil
@@ -733,10 +767,10 @@ module ActiveResource
733
767
  raise
734
768
  end
735
769
 
736
- alias_method :set_prefix, :prefix= #:nodoc:
770
+ alias_method :set_prefix, :prefix= # :nodoc:
737
771
 
738
- alias_method :set_element_name, :element_name= #:nodoc:
739
- alias_method :set_collection_name, :collection_name= #:nodoc:
772
+ alias_method :set_element_name, :element_name= # :nodoc:
773
+ alias_method :set_collection_name, :collection_name= # :nodoc:
740
774
 
741
775
  def format_extension
742
776
  include_format_in_path ? ".#{format.extension}" : ""
@@ -852,7 +886,7 @@ module ActiveResource
852
886
  "#{prefix(prefix_options)}#{collection_name}#{format_extension}#{query_string(query_options)}"
853
887
  end
854
888
 
855
- alias_method :set_primary_key, :primary_key= #:nodoc:
889
+ alias_method :set_primary_key, :primary_key= # :nodoc:
856
890
 
857
891
  # Builds a new, unsaved record using the default values from the remote server so
858
892
  # that it can be used with RESTful forms.
@@ -1050,7 +1084,6 @@ module ActiveResource
1050
1084
  end
1051
1085
 
1052
1086
  private
1053
-
1054
1087
  def check_prefix_options(prefix_options)
1055
1088
  p_options = HashWithIndifferentAccess.new(prefix_options)
1056
1089
  prefix_parameters.each do |p|
@@ -1060,23 +1093,26 @@ module ActiveResource
1060
1093
 
1061
1094
  # Find every resource
1062
1095
  def find_every(options)
1063
- begin
1096
+ params = options[:params]
1097
+ prefix_options, query_options = split_options(params)
1098
+
1099
+ response =
1064
1100
  case from = options[:from]
1065
1101
  when Symbol
1066
- instantiate_collection(get(from, options[:params]), options[:params])
1102
+ get(from, params)
1067
1103
  when String
1068
- path = "#{from}#{query_string(options[:params])}"
1069
- instantiate_collection(format.decode(connection.get(path, headers).body) || [], options[:params])
1104
+ path = "#{from}#{query_string(query_options)}"
1105
+ format.decode(connection.get(path, headers).body)
1070
1106
  else
1071
- prefix_options, query_options = split_options(options[:params])
1072
1107
  path = collection_path(prefix_options, query_options)
1073
- instantiate_collection((format.decode(connection.get(path, headers).body) || []), query_options, prefix_options)
1108
+ format.decode(connection.get(path, headers).body)
1074
1109
  end
1075
- rescue ActiveResource::ResourceNotFound
1076
- # Swallowing ResourceNotFound exceptions and return nil - as per
1077
- # ActiveRecord.
1078
- nil
1079
- end
1110
+
1111
+ instantiate_collection(response || [], query_options, prefix_options)
1112
+ rescue ActiveResource::ResourceNotFound
1113
+ # Swallowing ResourceNotFound exceptions and return nil - as per
1114
+ # ActiveRecord.
1115
+ nil
1080
1116
  end
1081
1117
 
1082
1118
  # Find a single resource from a one-off URL
@@ -1145,8 +1181,8 @@ module ActiveResource
1145
1181
  end
1146
1182
  end
1147
1183
 
1148
- attr_accessor :attributes #:nodoc:
1149
- attr_accessor :prefix_options #:nodoc:
1184
+ attr_accessor :attributes # :nodoc:
1185
+ attr_accessor :prefix_options # :nodoc:
1150
1186
 
1151
1187
  # If no schema has been defined for the class (see
1152
1188
  # <tt>ActiveResource::schema=</tt>), the default automatic schema is
@@ -1203,7 +1239,7 @@ module ActiveResource
1203
1239
  # not_ryan.hash # => {:not => "an ARes instance"}
1204
1240
  def clone
1205
1241
  # Clone all attributes except the pk and any nested ARes
1206
- cloned = Hash[attributes.reject { |k, v| k == self.class.primary_key || v.is_a?(ActiveResource::Base) }.map { |k, v| [k, v.clone] }]
1242
+ cloned = attributes.reject { |k, v| k == self.class.primary_key || v.is_a?(ActiveResource::Base) }.transform_values { |v| v.clone }
1207
1243
  # Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
1208
1244
  # attempts to convert hashes into member objects and arrays into collections of objects. We want
1209
1245
  # the raw objects to be cloned so we bypass load by directly setting the attributes hash.
@@ -1589,7 +1625,6 @@ module ActiveResource
1589
1625
  end
1590
1626
 
1591
1627
  private
1592
-
1593
1628
  # Determine whether the response is allowed to have a body per HTTP 1.1 spec section 4.4.1
1594
1629
  def response_code_allows_body?(c)
1595
1630
  !((100..199).include?(c) || [204, 304].include?(c))
@@ -1651,9 +1686,11 @@ module ActiveResource
1651
1686
 
1652
1687
  # Create and return a class definition for a resource inside the current resource
1653
1688
  def create_resource_for(resource_name)
1654
- resource = self.class.const_set(resource_name, Class.new(ActiveResource::Base))
1689
+ resource = Class.new(ActiveResource::Base)
1655
1690
  resource.prefix = self.class.prefix
1656
- resource.site = self.class.site
1691
+ resource.site = self.class.site
1692
+ self.class.const_set(resource_name, resource)
1693
+
1657
1694
  resource
1658
1695
  end
1659
1696
 
@@ -1661,7 +1698,7 @@ module ActiveResource
1661
1698
  self.class.__send__(:split_options, options)
1662
1699
  end
1663
1700
 
1664
- def method_missing(method_symbol, *arguments) #:nodoc:
1701
+ def method_missing(method_symbol, *arguments) # :nodoc:
1665
1702
  method_name = method_symbol.to_s
1666
1703
 
1667
1704
  if method_name =~ /(=|\?)$/
@@ -5,7 +5,7 @@ require "active_support/inflector"
5
5
 
6
6
  module ActiveResource # :nodoc:
7
7
  class Collection # :nodoc:
8
- SELF_DEFINE_METHODS = [:to_a, :collect!, :map!]
8
+ SELF_DEFINE_METHODS = [:to_a, :collect!, :map!, :all?]
9
9
  include Enumerable
10
10
  delegate :to_yaml, :all?, *(Array.instance_methods(false) - SELF_DEFINE_METHODS), to: :to_a
11
11
 
@@ -15,7 +15,7 @@ module ActiveResource # :nodoc:
15
15
  # ActiveResource::Collection is a wrapper to handle parsing index responses that
16
16
  # do not directly map to Rails conventions.
17
17
  #
18
- # You can define a custom class that inherets from ActiveResource::Collection
18
+ # You can define a custom class that inherits from ActiveResource::Collection
19
19
  # in order to to set the elements instance.
20
20
  #
21
21
  # GET /posts.json delivers following response body: