activeresource 2.1.2 → 2.2.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activeresource might be problematic. Click here for more details.
- data/CHANGELOG +9 -3
- data/README +1 -1
- data/Rakefile +3 -4
- data/lib/active_resource.rb +7 -10
- data/lib/active_resource/base.rb +170 -117
- data/lib/active_resource/connection.rb +27 -16
- data/lib/active_resource/custom_methods.rb +14 -13
- data/lib/active_resource/formats/json_format.rb +7 -7
- data/lib/active_resource/formats/xml_format.rb +9 -9
- data/lib/active_resource/http_mock.rb +2 -2
- data/lib/active_resource/validations.rb +15 -29
- data/lib/active_resource/version.rb +1 -1
- data/test/authorization_test.rb +8 -8
- data/test/base/custom_methods_test.rb +3 -2
- data/test/base/load_test.rb +2 -2
- data/test/base_test.rb +80 -50
- data/test/connection_test.rb +11 -3
- data/test/format_test.rb +40 -11
- metadata +4 -4
data/CHANGELOG
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
-
*2.1
|
1
|
+
*2.2.1 [RC2] (November 14th, 2008)*
|
2
2
|
|
3
|
-
*
|
3
|
+
* Fixed that ActiveResource#post would post an empty string when it shouldn't be posting anything #525 [Paolo Angelini]
|
4
4
|
|
5
5
|
|
6
|
-
*2.
|
6
|
+
*2.2.0 [RC1] (October 24th, 2008)*
|
7
|
+
|
8
|
+
* Add ActiveResource::Base#to_xml and ActiveResource::Base#to_json. #1011 [Rasik Pandey, Cody Fauser]
|
9
|
+
|
10
|
+
* Add ActiveResource::Base.find(:last). [#754 state:resolved] (Adrian Mugnolo)
|
11
|
+
|
12
|
+
* Fixed problems with the logger used if the logging string included %'s [#840 state:resolved] (Jamis Buck)
|
7
13
|
|
8
14
|
* Fixed Base#exists? to check status code as integer [#299 state:resolved] (Wes Oldenbeuving)
|
9
15
|
|
data/README
CHANGED
@@ -37,7 +37,7 @@ lifecycle methods that operate against a persistent store.
|
|
37
37
|
Person.exists?(1) #=> true
|
38
38
|
|
39
39
|
As you can see, the methods are quite similar to Active Record's methods for dealing with database
|
40
|
-
records. But rather than dealing with
|
40
|
+
records. But rather than dealing directly with a database record, you're dealing with HTTP resources (which may or may not be database records).
|
41
41
|
|
42
42
|
==== Protocol
|
43
43
|
|
data/Rakefile
CHANGED
@@ -5,7 +5,6 @@ require 'rake/rdoctask'
|
|
5
5
|
require 'rake/packagetask'
|
6
6
|
require 'rake/gempackagetask'
|
7
7
|
require 'rake/contrib/sshpublisher'
|
8
|
-
require 'rake/contrib/rubyforgepublisher'
|
9
8
|
|
10
9
|
require File.join(File.dirname(__FILE__), 'lib', 'active_resource', 'version')
|
11
10
|
|
@@ -66,7 +65,7 @@ spec = Gem::Specification.new do |s|
|
|
66
65
|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
67
66
|
end
|
68
67
|
|
69
|
-
s.add_dependency('activesupport', '= 2.
|
68
|
+
s.add_dependency('activesupport', '= 2.2.2' + PKG_BUILD)
|
70
69
|
|
71
70
|
s.require_path = 'lib'
|
72
71
|
s.autorequire = 'active_resource'
|
@@ -116,8 +115,8 @@ end
|
|
116
115
|
|
117
116
|
desc "Publish the beta gem"
|
118
117
|
task :pgem => [:package] do
|
119
|
-
Rake::SshFilePublisher.new("
|
120
|
-
`ssh
|
118
|
+
Rake::SshFilePublisher.new("gems.rubyonrails.org", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
119
|
+
`ssh gems.rubyonrails.org '/u/sites/gems/gemupdate.sh'`
|
121
120
|
end
|
122
121
|
|
123
122
|
desc "Publish the API documentation"
|
data/lib/active_resource.rb
CHANGED
@@ -21,16 +21,13 @@
|
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
#++
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
$:.unshift
|
24
|
+
begin
|
25
|
+
require 'active_support'
|
26
|
+
rescue LoadError
|
27
|
+
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
|
28
|
+
if File.directory?(activesupport_path)
|
29
|
+
$:.unshift activesupport_path
|
30
30
|
require 'active_support'
|
31
|
-
rescue LoadError
|
32
|
-
require 'rubygems'
|
33
|
-
gem 'activesupport'
|
34
31
|
end
|
35
32
|
end
|
36
33
|
|
@@ -44,4 +41,4 @@ module ActiveResource
|
|
44
41
|
include Validations
|
45
42
|
include CustomMethods
|
46
43
|
end
|
47
|
-
end
|
44
|
+
end
|
data/lib/active_resource/base.rb
CHANGED
@@ -13,48 +13,48 @@ module ActiveResource
|
|
13
13
|
# to Ruby objects, Active Resource only needs a class name that corresponds to the resource name (e.g., the class
|
14
14
|
# Person maps to the resources people, very similarly to Active Record) and a +site+ value, which holds the
|
15
15
|
# URI of the resources.
|
16
|
-
#
|
16
|
+
#
|
17
17
|
# class Person < ActiveResource::Base
|
18
18
|
# self.site = "http://api.people.com:3000/"
|
19
19
|
# end
|
20
|
-
#
|
20
|
+
#
|
21
21
|
# Now the Person class is mapped to RESTful resources located at <tt>http://api.people.com:3000/people/</tt>, and
|
22
|
-
# you can now use Active Resource's lifecycles methods to manipulate resources. In the case where you already have
|
22
|
+
# you can now use Active Resource's lifecycles methods to manipulate resources. In the case where you already have
|
23
23
|
# an existing model with the same name as the desired RESTful resource you can set the +element_name+ value.
|
24
24
|
#
|
25
25
|
# class PersonResource < ActiveResource::Base
|
26
26
|
# self.site = "http://api.people.com:3000/"
|
27
27
|
# self.element_name = "person"
|
28
28
|
# end
|
29
|
-
#
|
30
|
-
#
|
29
|
+
#
|
30
|
+
#
|
31
31
|
# == Lifecycle methods
|
32
32
|
#
|
33
33
|
# Active Resource exposes methods for creating, finding, updating, and deleting resources
|
34
34
|
# from REST web services.
|
35
|
-
#
|
35
|
+
#
|
36
36
|
# ryan = Person.new(:first => 'Ryan', :last => 'Daigle')
|
37
37
|
# ryan.save # => true
|
38
38
|
# ryan.id # => 2
|
39
39
|
# Person.exists?(ryan.id) # => true
|
40
40
|
# ryan.exists? # => true
|
41
|
-
#
|
41
|
+
#
|
42
42
|
# ryan = Person.find(1)
|
43
43
|
# # Resource holding our newly created Person object
|
44
|
-
#
|
44
|
+
#
|
45
45
|
# ryan.first = 'Rizzle'
|
46
46
|
# ryan.save # => true
|
47
|
-
#
|
47
|
+
#
|
48
48
|
# ryan.destroy # => true
|
49
49
|
#
|
50
50
|
# As you can see, these are very similar to Active Record's lifecycle methods for database records.
|
51
51
|
# You can read more about each of these methods in their respective documentation.
|
52
|
-
#
|
52
|
+
#
|
53
53
|
# === Custom REST methods
|
54
54
|
#
|
55
55
|
# Since simple CRUD/lifecycle methods can't accomplish every task, Active Resource also supports
|
56
56
|
# defining your own custom REST methods. To invoke them, Active Resource provides the <tt>get</tt>,
|
57
|
-
# <tt>post</tt>, <tt>put</tt> and <tt
|
57
|
+
# <tt>post</tt>, <tt>put</tt> and <tt>\delete</tt> methods where you can specify a custom REST method
|
58
58
|
# name to invoke.
|
59
59
|
#
|
60
60
|
# # POST to the custom 'register' REST method, i.e. POST /people/new/register.xml.
|
@@ -71,14 +71,14 @@ module ActiveResource
|
|
71
71
|
#
|
72
72
|
# # DELETE to 'fire' a person, i.e. DELETE /people/1/fire.xml.
|
73
73
|
# Person.find(1).delete(:fire)
|
74
|
-
#
|
74
|
+
#
|
75
75
|
# For more information on using custom REST methods, see the
|
76
76
|
# ActiveResource::CustomMethods documentation.
|
77
77
|
#
|
78
78
|
# == Validations
|
79
79
|
#
|
80
80
|
# You can validate resources client side by overriding validation methods in the base class.
|
81
|
-
#
|
81
|
+
#
|
82
82
|
# class Person < ActiveResource::Base
|
83
83
|
# self.site = "http://api.people.com:3000/"
|
84
84
|
# protected
|
@@ -86,19 +86,19 @@ module ActiveResource
|
|
86
86
|
# errors.add("last", "has invalid characters") unless last =~ /[a-zA-Z]*/
|
87
87
|
# end
|
88
88
|
# end
|
89
|
-
#
|
89
|
+
#
|
90
90
|
# See the ActiveResource::Validations documentation for more information.
|
91
91
|
#
|
92
92
|
# == Authentication
|
93
|
-
#
|
93
|
+
#
|
94
94
|
# Many REST APIs will require authentication, usually in the form of basic
|
95
95
|
# HTTP authentication. Authentication can be specified by:
|
96
96
|
# * putting the credentials in the URL for the +site+ variable.
|
97
|
-
#
|
97
|
+
#
|
98
98
|
# class Person < ActiveResource::Base
|
99
99
|
# self.site = "http://ryan:password@api.people.com:3000/"
|
100
100
|
# end
|
101
|
-
#
|
101
|
+
#
|
102
102
|
# * defining +user+ and/or +password+ variables
|
103
103
|
#
|
104
104
|
# class Person < ActiveResource::Base
|
@@ -107,35 +107,41 @@ module ActiveResource
|
|
107
107
|
# self.password = "password"
|
108
108
|
# end
|
109
109
|
#
|
110
|
-
# For obvious security reasons, it is probably best if such services are available
|
110
|
+
# For obvious security reasons, it is probably best if such services are available
|
111
111
|
# over HTTPS.
|
112
|
-
#
|
113
|
-
# Note: Some values cannot be provided in the URL passed to site. e.g. email addresses
|
114
|
-
# as usernames. In those situations you should use the
|
112
|
+
#
|
113
|
+
# Note: Some values cannot be provided in the URL passed to site. e.g. email addresses
|
114
|
+
# as usernames. In those situations you should use the separate user and password option.
|
115
115
|
# == Errors & Validation
|
116
116
|
#
|
117
117
|
# Error handling and validation is handled in much the same manner as you're used to seeing in
|
118
118
|
# Active Record. Both the response code in the HTTP response and the body of the response are used to
|
119
119
|
# indicate that an error occurred.
|
120
|
-
#
|
120
|
+
#
|
121
121
|
# === Resource errors
|
122
|
-
#
|
122
|
+
#
|
123
123
|
# When a GET is requested for a resource that does not exist, the HTTP <tt>404</tt> (Resource Not Found)
|
124
124
|
# response code will be returned from the server which will raise an ActiveResource::ResourceNotFound
|
125
125
|
# exception.
|
126
|
-
#
|
126
|
+
#
|
127
127
|
# # GET http://api.people.com:3000/people/999.xml
|
128
128
|
# ryan = Person.find(999) # 404, raises ActiveResource::ResourceNotFound
|
129
|
-
#
|
129
|
+
#
|
130
130
|
# <tt>404</tt> is just one of the HTTP error response codes that Active Resource will handle with its own exception. The
|
131
131
|
# following HTTP response codes will also result in these exceptions:
|
132
132
|
#
|
133
|
-
# * 200..399 - Valid response, no exception
|
133
|
+
# * 200..399 - Valid response, no exception (other than 301, 302)
|
134
|
+
# * 301, 302 - ActiveResource::Redirection
|
135
|
+
# * 400 - ActiveResource::BadRequest
|
136
|
+
# * 401 - ActiveResource::UnauthorizedAccess
|
137
|
+
# * 403 - ActiveResource::ForbiddenAccess
|
134
138
|
# * 404 - ActiveResource::ResourceNotFound
|
139
|
+
# * 405 - ActiveResource::MethodNotAllowed
|
135
140
|
# * 409 - ActiveResource::ResourceConflict
|
136
141
|
# * 422 - ActiveResource::ResourceInvalid (rescued by save as validation errors)
|
137
142
|
# * 401..499 - ActiveResource::ClientError
|
138
143
|
# * 500..599 - ActiveResource::ServerError
|
144
|
+
# * Other - ActiveResource::ConnectionError
|
139
145
|
#
|
140
146
|
# These custom exceptions allow you to deal with resource errors more naturally and with more precision
|
141
147
|
# rather than returning a general HTTP error. For example:
|
@@ -149,17 +155,17 @@ module ActiveResource
|
|
149
155
|
# end
|
150
156
|
#
|
151
157
|
# === Validation errors
|
152
|
-
#
|
158
|
+
#
|
153
159
|
# Active Resource supports validations on resources and will return errors if any these validations fail
|
154
|
-
# (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by
|
160
|
+
# (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by
|
155
161
|
# a response code of <tt>422</tt> and an XML representation of the validation errors. The save operation will
|
156
162
|
# then fail (with a <tt>false</tt> return value) and the validation errors can be accessed on the resource in question.
|
157
|
-
#
|
163
|
+
#
|
158
164
|
# ryan = Person.find(1)
|
159
165
|
# ryan.first # => ''
|
160
166
|
# ryan.save # => false
|
161
167
|
#
|
162
|
-
# # When
|
168
|
+
# # When
|
163
169
|
# # PUT http://api.people.com:3000/people/1.xml
|
164
170
|
# # is requested with invalid values, the response is:
|
165
171
|
# #
|
@@ -169,13 +175,13 @@ module ActiveResource
|
|
169
175
|
#
|
170
176
|
# ryan.errors.invalid?(:first) # => true
|
171
177
|
# ryan.errors.full_messages # => ['First cannot be empty']
|
172
|
-
#
|
178
|
+
#
|
173
179
|
# Learn more about Active Resource's validation features in the ActiveResource::Validations documentation.
|
174
180
|
#
|
175
181
|
# === Timeouts
|
176
182
|
#
|
177
183
|
# Active Resource relies on HTTP to access RESTful APIs and as such is inherently susceptible to slow or
|
178
|
-
# unresponsive servers. In such cases, your Active Resource method calls could timeout. You can control the
|
184
|
+
# unresponsive servers. In such cases, your Active Resource method calls could \timeout. You can control the
|
179
185
|
# amount of time before Active Resource times out with the +timeout+ variable.
|
180
186
|
#
|
181
187
|
# class Person < ActiveResource::Base
|
@@ -189,7 +195,7 @@ module ActiveResource
|
|
189
195
|
# http://en.wikipedia.org/wiki/Fail-fast) rather than cause cascading failures that could incapacitate your
|
190
196
|
# server.
|
191
197
|
#
|
192
|
-
# When a timeout occurs, an ActiveResource::TimeoutError is raised. You should rescue from
|
198
|
+
# When a \timeout occurs, an ActiveResource::TimeoutError is raised. You should rescue from
|
193
199
|
# ActiveResource::TimeoutError in your Active Resource method calls.
|
194
200
|
#
|
195
201
|
# Internally, Active Resource relies on Ruby's Net::HTTP library to make HTTP requests. Setting +timeout+
|
@@ -200,7 +206,7 @@ module ActiveResource
|
|
200
206
|
cattr_accessor :logger
|
201
207
|
|
202
208
|
class << self
|
203
|
-
# Gets the URI of the REST resources to map for this class. The site variable is required
|
209
|
+
# Gets the URI of the REST resources to map for this class. The site variable is required for
|
204
210
|
# Active Resource's mapping to work.
|
205
211
|
def site
|
206
212
|
# Not using superclass_delegating_reader because don't want subclasses to modify superclass instance
|
@@ -226,7 +232,7 @@ module ActiveResource
|
|
226
232
|
end
|
227
233
|
|
228
234
|
# Sets the URI of the REST resources to map for this class to the value in the +site+ argument.
|
229
|
-
# The site variable is required Active Resource's mapping to work.
|
235
|
+
# The site variable is required for Active Resource's mapping to work.
|
230
236
|
def site=(site)
|
231
237
|
@connection = nil
|
232
238
|
if site.nil?
|
@@ -238,7 +244,7 @@ module ActiveResource
|
|
238
244
|
end
|
239
245
|
end
|
240
246
|
|
241
|
-
# Gets the user for REST HTTP authentication.
|
247
|
+
# Gets the \user for REST HTTP authentication.
|
242
248
|
def user
|
243
249
|
# Not using superclass_delegating_reader. See +site+ for explanation
|
244
250
|
if defined?(@user)
|
@@ -248,13 +254,13 @@ module ActiveResource
|
|
248
254
|
end
|
249
255
|
end
|
250
256
|
|
251
|
-
# Sets the user for REST HTTP authentication.
|
257
|
+
# Sets the \user for REST HTTP authentication.
|
252
258
|
def user=(user)
|
253
259
|
@connection = nil
|
254
260
|
@user = user
|
255
261
|
end
|
256
262
|
|
257
|
-
# Gets the password for REST HTTP authentication.
|
263
|
+
# Gets the \password for REST HTTP authentication.
|
258
264
|
def password
|
259
265
|
# Not using superclass_delegating_reader. See +site+ for explanation
|
260
266
|
if defined?(@password)
|
@@ -264,7 +270,7 @@ module ActiveResource
|
|
264
270
|
end
|
265
271
|
end
|
266
272
|
|
267
|
-
# Sets the password for REST HTTP authentication.
|
273
|
+
# Sets the \password for REST HTTP authentication.
|
268
274
|
def password=(password)
|
269
275
|
@connection = nil
|
270
276
|
@password = password
|
@@ -280,16 +286,16 @@ module ActiveResource
|
|
280
286
|
#
|
281
287
|
# Default format is <tt>:xml</tt>.
|
282
288
|
def format=(mime_type_reference_or_format)
|
283
|
-
format = mime_type_reference_or_format.is_a?(Symbol) ?
|
289
|
+
format = mime_type_reference_or_format.is_a?(Symbol) ?
|
284
290
|
ActiveResource::Formats[mime_type_reference_or_format] : mime_type_reference_or_format
|
285
291
|
|
286
|
-
write_inheritable_attribute(
|
292
|
+
write_inheritable_attribute(:format, format)
|
287
293
|
connection.format = format if site
|
288
294
|
end
|
289
295
|
|
290
296
|
# Returns the current format, default is ActiveResource::Formats::XmlFormat.
|
291
|
-
def format
|
292
|
-
read_inheritable_attribute(
|
297
|
+
def format
|
298
|
+
read_inheritable_attribute(:format) || ActiveResource::Formats[:xml]
|
293
299
|
end
|
294
300
|
|
295
301
|
# Sets the number of seconds after which requests to the REST API should time out.
|
@@ -298,7 +304,7 @@ module ActiveResource
|
|
298
304
|
@timeout = timeout
|
299
305
|
end
|
300
306
|
|
301
|
-
# Gets
|
307
|
+
# Gets the number of seconds after which requests to the REST API should time out.
|
302
308
|
def timeout
|
303
309
|
if defined?(@timeout)
|
304
310
|
@timeout
|
@@ -307,8 +313,8 @@ module ActiveResource
|
|
307
313
|
end
|
308
314
|
end
|
309
315
|
|
310
|
-
# An instance of ActiveResource::Connection that is the base connection to the remote service.
|
311
|
-
# The +refresh+ parameter toggles whether or not the connection is refreshed at every request
|
316
|
+
# An instance of ActiveResource::Connection that is the base \connection to the remote service.
|
317
|
+
# The +refresh+ parameter toggles whether or not the \connection is refreshed at every request
|
312
318
|
# or not (defaults to <tt>false</tt>).
|
313
319
|
def connection(refresh = false)
|
314
320
|
if defined?(@connection) || superclass == Object
|
@@ -333,8 +339,8 @@ module ActiveResource
|
|
333
339
|
attr_accessor_with_default(:collection_name) { element_name.pluralize } #:nodoc:
|
334
340
|
attr_accessor_with_default(:primary_key, 'id') #:nodoc:
|
335
341
|
|
336
|
-
# Gets the prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>)
|
337
|
-
# This method is regenerated at runtime based on what the prefix is set to.
|
342
|
+
# Gets the \prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>)
|
343
|
+
# This method is regenerated at runtime based on what the \prefix is set to.
|
338
344
|
def prefix(options={})
|
339
345
|
default = site.path
|
340
346
|
default << '/' unless default[-1..-1] == '/'
|
@@ -343,14 +349,14 @@ module ActiveResource
|
|
343
349
|
prefix(options)
|
344
350
|
end
|
345
351
|
|
346
|
-
# An attribute reader for the source string for the resource path prefix. This
|
347
|
-
# method is regenerated at runtime based on what the prefix is set to.
|
352
|
+
# An attribute reader for the source string for the resource path \prefix. This
|
353
|
+
# method is regenerated at runtime based on what the \prefix is set to.
|
348
354
|
def prefix_source
|
349
355
|
prefix # generate #prefix and #prefix_source methods first
|
350
356
|
prefix_source
|
351
357
|
end
|
352
358
|
|
353
|
-
# Sets the prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>).
|
359
|
+
# Sets the \prefix for a resource's nested URL (e.g., <tt>prefix/collectionname/1.xml</tt>).
|
354
360
|
# Default value is <tt>site.path</tt>.
|
355
361
|
def prefix=(value = '/')
|
356
362
|
# Replace :placeholders with '#{embedded options[:lookups]}'
|
@@ -376,29 +382,29 @@ module ActiveResource
|
|
376
382
|
alias_method :set_collection_name, :collection_name= #:nodoc:
|
377
383
|
|
378
384
|
# Gets the element path for the given ID in +id+. If the +query_options+ parameter is omitted, Rails
|
379
|
-
# will split from the prefix options.
|
385
|
+
# will split from the \prefix options.
|
380
386
|
#
|
381
387
|
# ==== Options
|
382
|
-
# +prefix_options+ - A hash to add a prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
|
388
|
+
# +prefix_options+ - A \hash to add a \prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
|
383
389
|
# would yield a URL like <tt>/accounts/19/purchases.xml</tt>).
|
384
|
-
# +query_options+ - A hash to add items to the query string for the request.
|
390
|
+
# +query_options+ - A \hash to add items to the query string for the request.
|
385
391
|
#
|
386
392
|
# ==== Examples
|
387
|
-
# Post.element_path(1)
|
393
|
+
# Post.element_path(1)
|
388
394
|
# # => /posts/1.xml
|
389
395
|
#
|
390
|
-
# Comment.element_path(1, :post_id => 5)
|
396
|
+
# Comment.element_path(1, :post_id => 5)
|
391
397
|
# # => /posts/5/comments/1.xml
|
392
398
|
#
|
393
|
-
# Comment.element_path(1, :post_id => 5, :active => 1)
|
399
|
+
# Comment.element_path(1, :post_id => 5, :active => 1)
|
394
400
|
# # => /posts/5/comments/1.xml?active=1
|
395
401
|
#
|
396
|
-
# Comment.element_path(1, {:post_id => 5}, {:active => 1})
|
402
|
+
# Comment.element_path(1, {:post_id => 5}, {:active => 1})
|
397
403
|
# # => /posts/5/comments/1.xml?active=1
|
398
404
|
#
|
399
405
|
def element_path(id, prefix_options = {}, query_options = nil)
|
400
406
|
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
|
401
|
-
"#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
|
407
|
+
"#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
|
402
408
|
end
|
403
409
|
|
404
410
|
# Gets the collection path for the REST resources. If the +query_options+ parameter is omitted, Rails
|
@@ -413,13 +419,13 @@ module ActiveResource
|
|
413
419
|
# Post.collection_path
|
414
420
|
# # => /posts.xml
|
415
421
|
#
|
416
|
-
# Comment.collection_path(:post_id => 5)
|
422
|
+
# Comment.collection_path(:post_id => 5)
|
417
423
|
# # => /posts/5/comments.xml
|
418
424
|
#
|
419
|
-
# Comment.collection_path(:post_id => 5, :active => 1)
|
425
|
+
# Comment.collection_path(:post_id => 5, :active => 1)
|
420
426
|
# # => /posts/5/comments.xml?active=1
|
421
427
|
#
|
422
|
-
# Comment.collection_path({:post_id => 5}, {:active => 1})
|
428
|
+
# Comment.collection_path({:post_id => 5}, {:active => 1})
|
423
429
|
# # => /posts/5/comments.xml?active=1
|
424
430
|
#
|
425
431
|
def collection_path(prefix_options = {}, query_options = nil)
|
@@ -429,16 +435,16 @@ module ActiveResource
|
|
429
435
|
|
430
436
|
alias_method :set_primary_key, :primary_key= #:nodoc:
|
431
437
|
|
432
|
-
#
|
438
|
+
# Creates a new resource instance and makes a request to the remote service
|
433
439
|
# that it be saved, making it equivalent to the following simultaneous calls:
|
434
440
|
#
|
435
441
|
# ryan = Person.new(:first => 'ryan')
|
436
442
|
# ryan.save
|
437
443
|
#
|
438
|
-
#
|
439
|
-
# exception will be raised (see save). If the resource is invalid and
|
440
|
-
# has not been saved then valid
|
441
|
-
# while new
|
444
|
+
# Returns the newly created resource. If a failure has occurred an
|
445
|
+
# exception will be raised (see <tt>save</tt>). If the resource is invalid and
|
446
|
+
# has not been saved then <tt>valid?</tt> will return <tt>false</tt>,
|
447
|
+
# while <tt>new?</tt> will still return <tt>true</tt>.
|
442
448
|
#
|
443
449
|
# ==== Examples
|
444
450
|
# Person.create(:name => 'Jeremy', :email => 'myname@nospam.com', :enabled => true)
|
@@ -454,50 +460,54 @@ module ActiveResource
|
|
454
460
|
# that_guy.valid? # => false
|
455
461
|
# that_guy.new? # => true
|
456
462
|
def create(attributes = {})
|
457
|
-
returning(self.new(attributes)) { |res| res.save }
|
463
|
+
returning(self.new(attributes)) { |res| res.save }
|
458
464
|
end
|
459
465
|
|
460
466
|
# Core method for finding resources. Used similarly to Active Record's +find+ method.
|
461
467
|
#
|
462
468
|
# ==== Arguments
|
463
|
-
# The first argument is considered to be the scope of the query. That is, how many
|
469
|
+
# The first argument is considered to be the scope of the query. That is, how many
|
464
470
|
# resources are returned from the request. It can be one of the following.
|
465
471
|
#
|
466
472
|
# * <tt>:one</tt> - Returns a single resource.
|
467
473
|
# * <tt>:first</tt> - Returns the first resource found.
|
474
|
+
# * <tt>:last</tt> - Returns the last resource found.
|
468
475
|
# * <tt>:all</tt> - Returns every resource that matches the request.
|
469
|
-
#
|
476
|
+
#
|
470
477
|
# ==== Options
|
471
478
|
#
|
472
479
|
# * <tt>:from</tt> - Sets the path or custom method that resources will be fetched from.
|
473
|
-
# * <tt>:params</tt> - Sets query and prefix (nested URL) parameters.
|
480
|
+
# * <tt>:params</tt> - Sets query and \prefix (nested URL) parameters.
|
474
481
|
#
|
475
482
|
# ==== Examples
|
476
|
-
# Person.find(1)
|
483
|
+
# Person.find(1)
|
477
484
|
# # => GET /people/1.xml
|
478
485
|
#
|
479
|
-
# Person.find(:all)
|
486
|
+
# Person.find(:all)
|
480
487
|
# # => GET /people.xml
|
481
488
|
#
|
482
|
-
# Person.find(:all, :params => { :title => "CEO" })
|
489
|
+
# Person.find(:all, :params => { :title => "CEO" })
|
483
490
|
# # => GET /people.xml?title=CEO
|
484
491
|
#
|
485
|
-
# Person.find(:first, :from => :managers)
|
492
|
+
# Person.find(:first, :from => :managers)
|
493
|
+
# # => GET /people/managers.xml
|
494
|
+
#
|
495
|
+
# Person.find(:last, :from => :managers)
|
486
496
|
# # => GET /people/managers.xml
|
487
497
|
#
|
488
|
-
# Person.find(:all, :from => "/companies/1/people.xml")
|
498
|
+
# Person.find(:all, :from => "/companies/1/people.xml")
|
489
499
|
# # => GET /companies/1/people.xml
|
490
500
|
#
|
491
|
-
# Person.find(:one, :from => :leader)
|
501
|
+
# Person.find(:one, :from => :leader)
|
492
502
|
# # => GET /people/leader.xml
|
493
503
|
#
|
494
504
|
# Person.find(:all, :from => :developers, :params => { :language => 'ruby' })
|
495
505
|
# # => GET /people/developers.xml?language=ruby
|
496
506
|
#
|
497
|
-
# Person.find(:one, :from => "/companies/1/manager.xml")
|
507
|
+
# Person.find(:one, :from => "/companies/1/manager.xml")
|
498
508
|
# # => GET /companies/1/manager.xml
|
499
509
|
#
|
500
|
-
# StreetAddress.find(1, :params => { :person_id => 1 })
|
510
|
+
# StreetAddress.find(1, :params => { :person_id => 1 })
|
501
511
|
# # => GET /people/1/street_addresses/1.xml
|
502
512
|
def find(*arguments)
|
503
513
|
scope = arguments.slice!(0)
|
@@ -506,6 +516,7 @@ module ActiveResource
|
|
506
516
|
case scope
|
507
517
|
when :all then find_every(options)
|
508
518
|
when :first then find_every(options).first
|
519
|
+
when :last then find_every(options).last
|
509
520
|
when :one then find_one(options)
|
510
521
|
else find_single(scope, options)
|
511
522
|
end
|
@@ -514,7 +525,7 @@ module ActiveResource
|
|
514
525
|
# Deletes the resources with the ID in the +id+ parameter.
|
515
526
|
#
|
516
527
|
# ==== Options
|
517
|
-
# All options specify prefix and query parameters.
|
528
|
+
# All options specify \prefix and query parameters.
|
518
529
|
#
|
519
530
|
# ==== Examples
|
520
531
|
# Event.delete(2) # sends DELETE /events/2
|
@@ -563,7 +574,7 @@ module ActiveResource
|
|
563
574
|
instantiate_collection( (connection.get(path, headers) || []), prefix_options )
|
564
575
|
end
|
565
576
|
end
|
566
|
-
|
577
|
+
|
567
578
|
# Find a single resource from a one-off URL
|
568
579
|
def find_one(options)
|
569
580
|
case from = options[:from]
|
@@ -581,7 +592,7 @@ module ActiveResource
|
|
581
592
|
path = element_path(scope, prefix_options, query_options)
|
582
593
|
instantiate_record(connection.get(path, headers), prefix_options)
|
583
594
|
end
|
584
|
-
|
595
|
+
|
585
596
|
def instantiate_collection(collection, prefix_options = {})
|
586
597
|
collection.collect! { |record| instantiate_record(record, prefix_options) }
|
587
598
|
end
|
@@ -605,10 +616,10 @@ module ActiveResource
|
|
605
616
|
|
606
617
|
# Builds the query string for the request.
|
607
618
|
def query_string(options)
|
608
|
-
"?#{options.to_query}" unless options.nil? || options.empty?
|
619
|
+
"?#{options.to_query}" unless options.nil? || options.empty?
|
609
620
|
end
|
610
621
|
|
611
|
-
# split an option hash into two hashes, one containing the prefix options,
|
622
|
+
# split an option hash into two hashes, one containing the prefix options,
|
612
623
|
# and the other containing the leftovers.
|
613
624
|
def split_options(options = {})
|
614
625
|
prefix_options, query_options = {}, {}
|
@@ -625,8 +636,8 @@ module ActiveResource
|
|
625
636
|
attr_accessor :attributes #:nodoc:
|
626
637
|
attr_accessor :prefix_options #:nodoc:
|
627
638
|
|
628
|
-
# Constructor method for new resources; the optional +attributes+ parameter takes a hash
|
629
|
-
# of attributes for the new resource.
|
639
|
+
# Constructor method for \new resources; the optional +attributes+ parameter takes a \hash
|
640
|
+
# of attributes for the \new resource.
|
630
641
|
#
|
631
642
|
# ==== Examples
|
632
643
|
# my_course = Course.new
|
@@ -642,8 +653,8 @@ module ActiveResource
|
|
642
653
|
load(attributes)
|
643
654
|
end
|
644
655
|
|
645
|
-
# Returns a clone of the resource that hasn't been assigned an +id+ yet and
|
646
|
-
# is treated as a new resource.
|
656
|
+
# Returns a \clone of the resource that hasn't been assigned an +id+ yet and
|
657
|
+
# is treated as a \new resource.
|
647
658
|
#
|
648
659
|
# ryan = Person.find(1)
|
649
660
|
# not_ryan = ryan.clone
|
@@ -657,7 +668,7 @@ module ActiveResource
|
|
657
668
|
# ryan = Person.find(1)
|
658
669
|
# ryan.address = StreetAddress.find(1, :person_id => ryan.id)
|
659
670
|
# ryan.hash = {:not => "an ARes instance"}
|
660
|
-
#
|
671
|
+
#
|
661
672
|
# not_ryan = ryan.clone
|
662
673
|
# not_ryan.new? # => true
|
663
674
|
# not_ryan.address # => NoMethodError
|
@@ -678,7 +689,7 @@ module ActiveResource
|
|
678
689
|
end
|
679
690
|
|
680
691
|
|
681
|
-
# A method to determine if the resource a new object (i.e., it has not been POSTed to the remote service yet).
|
692
|
+
# A method to determine if the resource a \new object (i.e., it has not been POSTed to the remote service yet).
|
682
693
|
#
|
683
694
|
# ==== Examples
|
684
695
|
# not_new = Computer.create(:brand => 'Apple', :make => 'MacBook', :vendor => 'MacMall')
|
@@ -694,12 +705,12 @@ module ActiveResource
|
|
694
705
|
id.nil?
|
695
706
|
end
|
696
707
|
|
697
|
-
#
|
708
|
+
# Gets the <tt>\id</tt> attribute of the resource.
|
698
709
|
def id
|
699
710
|
attributes[self.class.primary_key]
|
700
711
|
end
|
701
712
|
|
702
|
-
#
|
713
|
+
# Sets the <tt>\id</tt> attribute of the resource.
|
703
714
|
def id=(id)
|
704
715
|
attributes[self.class.primary_key] = id
|
705
716
|
end
|
@@ -709,7 +720,7 @@ module ActiveResource
|
|
709
720
|
id && id.to_s
|
710
721
|
end
|
711
722
|
|
712
|
-
# Test for equality. Resource are equal if and only if +other+ is the same object or
|
723
|
+
# Test for equality. Resource are equal if and only if +other+ is the same object or
|
713
724
|
# is an instance of the same class, is not <tt>new?</tt>, and has the same +id+.
|
714
725
|
#
|
715
726
|
# ==== Examples
|
@@ -740,12 +751,12 @@ module ActiveResource
|
|
740
751
|
self == other
|
741
752
|
end
|
742
753
|
|
743
|
-
# Delegates to id in order to allow two resources of the same type and id to work with something like:
|
754
|
+
# Delegates to id in order to allow two resources of the same type and \id to work with something like:
|
744
755
|
# [Person.find(1), Person.find(2)] & [Person.find(1), Person.find(4)] # => [Person.find(1)]
|
745
756
|
def hash
|
746
757
|
id.hash
|
747
758
|
end
|
748
|
-
|
759
|
+
|
749
760
|
# Duplicate the current resource without saving it.
|
750
761
|
#
|
751
762
|
# ==== Examples
|
@@ -765,9 +776,9 @@ module ActiveResource
|
|
765
776
|
end
|
766
777
|
end
|
767
778
|
|
768
|
-
# A method to save (+POST+) or update (+PUT+) a resource. It delegates to +create+ if a new object,
|
769
|
-
# +update+ if it is existing. If the response to the save includes a body, it will be assumed that this body
|
770
|
-
# is XML for the final object as it looked after the save (which would include attributes like +created_at+
|
779
|
+
# A method to \save (+POST+) or \update (+PUT+) a resource. It delegates to +create+ if a \new object,
|
780
|
+
# +update+ if it is existing. If the response to the \save includes a body, it will be assumed that this body
|
781
|
+
# is XML for the final object as it looked after the \save (which would include attributes like +created_at+
|
771
782
|
# that weren't part of the original submit).
|
772
783
|
#
|
773
784
|
# ==== Examples
|
@@ -789,7 +800,7 @@ module ActiveResource
|
|
789
800
|
# my_person = Person.find(my_id)
|
790
801
|
# my_person.destroy
|
791
802
|
# Person.find(my_id) # 404 (Resource Not Found)
|
792
|
-
#
|
803
|
+
#
|
793
804
|
# new_person = Person.create(:name => 'James')
|
794
805
|
# new_id = new_person.id # => 7
|
795
806
|
# new_person.destroy
|
@@ -815,7 +826,7 @@ module ActiveResource
|
|
815
826
|
# Person.delete(guys_id)
|
816
827
|
# that_guy.exists? # => false
|
817
828
|
def exists?
|
818
|
-
!new? && self.class.exists?(to_param, :params => prefix_options)
|
829
|
+
!new? && self.class.exists?(to_param, :params => prefix_options)
|
819
830
|
end
|
820
831
|
|
821
832
|
# A method to convert the the resource to an XML string.
|
@@ -828,7 +839,7 @@ module ActiveResource
|
|
828
839
|
# * <tt>:indent</tt> - Set the indent level for the XML output (default is +2+).
|
829
840
|
# * <tt>:dasherize</tt> - Boolean option to determine whether or not element names should
|
830
841
|
# replace underscores with dashes (default is <tt>false</tt>).
|
831
|
-
# * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder
|
842
|
+
# * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder
|
832
843
|
# that generates the XML declaration (default is <tt>false</tt>).
|
833
844
|
#
|
834
845
|
# ==== Examples
|
@@ -847,12 +858,53 @@ module ActiveResource
|
|
847
858
|
attributes.to_xml({:root => self.class.element_name}.merge(options))
|
848
859
|
end
|
849
860
|
|
850
|
-
#
|
861
|
+
# Returns a JSON string representing the model. Some configuration is
|
862
|
+
# available through +options+.
|
863
|
+
#
|
864
|
+
# ==== Options
|
865
|
+
# The +options+ are passed to the +to_json+ method on each
|
866
|
+
# attribute, so the same options as the +to_json+ methods in
|
867
|
+
# Active Support.
|
868
|
+
#
|
869
|
+
# * <tt>:only</tt> - Only include the specified attribute or list of
|
870
|
+
# attributes in the serialized output. Attribute names must be specified
|
871
|
+
# as strings.
|
872
|
+
# * <tt>:except</tt> - Do not include the specified attribute or list of
|
873
|
+
# attributes in the serialized output. Attribute names must be specified
|
874
|
+
# as strings.
|
875
|
+
#
|
876
|
+
# ==== Examples
|
877
|
+
# person = Person.new(:first_name => "Jim", :last_name => "Smith")
|
878
|
+
# person.to_json
|
879
|
+
# # => {"first_name": "Jim", "last_name": "Smith"}
|
880
|
+
#
|
881
|
+
# person.to_json(:only => ["first_name"])
|
882
|
+
# # => {"first_name": "Jim"}
|
883
|
+
#
|
884
|
+
# person.to_json(:except => ["first_name"])
|
885
|
+
# # => {"last_name": "Smith"}
|
886
|
+
def to_json(options={})
|
887
|
+
attributes.to_json(options)
|
888
|
+
end
|
889
|
+
|
890
|
+
# Returns the serialized string representation of the resource in the configured
|
891
|
+
# serialization format specified in ActiveResource::Base.format. The options
|
892
|
+
# applicable depend on the configured encoding format.
|
893
|
+
def encode(options={})
|
894
|
+
case self.class.format
|
895
|
+
when ActiveResource::Formats[:xml]
|
896
|
+
self.class.format.encode(attributes, {:root => self.class.element_name}.merge(options))
|
897
|
+
else
|
898
|
+
self.class.format.encode(attributes, options)
|
899
|
+
end
|
900
|
+
end
|
901
|
+
|
902
|
+
# A method to \reload the attributes of this object from the remote web service.
|
851
903
|
#
|
852
904
|
# ==== Examples
|
853
905
|
# my_branch = Branch.find(:first)
|
854
906
|
# my_branch.name # => "Wislon Raod"
|
855
|
-
#
|
907
|
+
#
|
856
908
|
# # Another client fixes the typo...
|
857
909
|
#
|
858
910
|
# my_branch.name # => "Wislon Raod"
|
@@ -862,12 +914,13 @@ module ActiveResource
|
|
862
914
|
self.load(self.class.find(to_param, :params => @prefix_options).attributes)
|
863
915
|
end
|
864
916
|
|
865
|
-
# A method to manually load attributes from a hash. Recursively loads collections of
|
866
|
-
# resources. This method is called in +initialize+ and +create+ when a hash of attributes
|
917
|
+
# A method to manually load attributes from a \hash. Recursively loads collections of
|
918
|
+
# resources. This method is called in +initialize+ and +create+ when a \hash of attributes
|
867
919
|
# is provided.
|
868
920
|
#
|
869
921
|
# ==== Examples
|
870
922
|
# my_attrs = {:name => 'J&J Textiles', :industry => 'Cloth and textiles'}
|
923
|
+
# my_attrs = {:name => 'Marty', :colors => ["red", "green", "blue"]}
|
871
924
|
#
|
872
925
|
# the_supplier = Supplier.find(:first)
|
873
926
|
# the_supplier.name # => 'J&M Textiles'
|
@@ -890,7 +943,7 @@ module ActiveResource
|
|
890
943
|
case value
|
891
944
|
when Array
|
892
945
|
resource = find_or_create_resource_for_collection(key)
|
893
|
-
value.map { |attrs| resource.new(attrs) }
|
946
|
+
value.map { |attrs| attrs.is_a?(String) ? attrs.dup : resource.new(attrs) }
|
894
947
|
when Hash
|
895
948
|
resource = find_or_create_resource_for(key)
|
896
949
|
resource.new(value)
|
@@ -900,19 +953,19 @@ module ActiveResource
|
|
900
953
|
end
|
901
954
|
self
|
902
955
|
end
|
903
|
-
|
956
|
+
|
904
957
|
# For checking <tt>respond_to?</tt> without searching the attributes (which is faster).
|
905
958
|
alias_method :respond_to_without_attributes?, :respond_to?
|
906
959
|
|
907
960
|
# A method to determine if an object responds to a message (e.g., a method call). In Active Resource, a Person object with a
|
908
|
-
# +name+ attribute can answer <tt>true</tt> to <tt>my_person.respond_to?(
|
909
|
-
# <tt>my_person.respond_to?(
|
961
|
+
# +name+ attribute can answer <tt>true</tt> to <tt>my_person.respond_to?(:name)</tt>, <tt>my_person.respond_to?(:name=)</tt>, and
|
962
|
+
# <tt>my_person.respond_to?(:name?)</tt>.
|
910
963
|
def respond_to?(method, include_priv = false)
|
911
964
|
method_name = method.to_s
|
912
965
|
if attributes.nil?
|
913
966
|
return super
|
914
967
|
elsif attributes.has_key?(method_name)
|
915
|
-
return true
|
968
|
+
return true
|
916
969
|
elsif ['?','='].include?(method_name.last) && attributes.has_key?(method_name.first(-1))
|
917
970
|
return true
|
918
971
|
end
|
@@ -920,7 +973,7 @@ module ActiveResource
|
|
920
973
|
# would return true for generated readers, even if the attribute wasn't present
|
921
974
|
super
|
922
975
|
end
|
923
|
-
|
976
|
+
|
924
977
|
|
925
978
|
protected
|
926
979
|
def connection(refresh = false)
|
@@ -929,19 +982,19 @@ module ActiveResource
|
|
929
982
|
|
930
983
|
# Update the resource on the remote service.
|
931
984
|
def update
|
932
|
-
returning connection.put(element_path(prefix_options),
|
985
|
+
returning connection.put(element_path(prefix_options), encode, self.class.headers) do |response|
|
933
986
|
load_attributes_from_response(response)
|
934
987
|
end
|
935
988
|
end
|
936
989
|
|
937
|
-
# Create (i.e., save to the remote service) the new resource.
|
990
|
+
# Create (i.e., \save to the remote service) the \new resource.
|
938
991
|
def create
|
939
|
-
returning connection.post(collection_path,
|
992
|
+
returning connection.post(collection_path, encode, self.class.headers) do |response|
|
940
993
|
self.id = id_from_response(response)
|
941
994
|
load_attributes_from_response(response)
|
942
995
|
end
|
943
996
|
end
|
944
|
-
|
997
|
+
|
945
998
|
def load_attributes_from_response(response)
|
946
999
|
if response['Content-Length'] != "0" && response.body.strip.size > 0
|
947
1000
|
load(self.class.format.decode(response.body))
|
@@ -966,7 +1019,7 @@ module ActiveResource
|
|
966
1019
|
def find_or_create_resource_for_collection(name)
|
967
1020
|
find_or_create_resource_for(name.to_s.singularize)
|
968
1021
|
end
|
969
|
-
|
1022
|
+
|
970
1023
|
# Tries to find a resource in a non empty list of nested modules
|
971
1024
|
# Raises a NameError if it was not found in any of the given nested modules
|
972
1025
|
def find_resource_in_modules(resource_name, module_names)
|
@@ -1002,7 +1055,7 @@ module ActiveResource
|
|
1002
1055
|
end
|
1003
1056
|
|
1004
1057
|
def split_options(options = {})
|
1005
|
-
self.class.
|
1058
|
+
self.class.__send__(:split_options, options)
|
1006
1059
|
end
|
1007
1060
|
|
1008
1061
|
def method_missing(method_symbol, *arguments) #:nodoc:
|