activeresource 2.0.5 → 2.1.0

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 CHANGED
@@ -1,9 +1,12 @@
1
- *2.0.5* (October 19th, 2008)
1
+ *2.1.0 (May 31st, 2008)*
2
2
 
3
- * Included in Rails 2.0.5
3
+ * Fixed response logging to use length instead of the entire thing (seangeo) [#27]
4
4
 
5
+ * Fixed that to_param should be used and honored instead of hardcoding the id #11406 [gspiers]
5
6
 
6
- *2.0.4* (2nd September 2008)
7
+ * Improve documentation. [Radar, Jan De Poorter, chuyeow, xaviershay, danger, miloops, Xavier Noria, Sunny Ripert]
8
+
9
+ * Use HEAD instead of GET in exists? [bscofield]
7
10
 
8
11
  * Fix small documentation typo. Closes #10670 [l.guidi]
9
12
 
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'rake/rdoctask'
5
5
  require 'rake/packagetask'
6
6
  require 'rake/gempackagetask'
7
7
  require 'rake/contrib/sshpublisher'
8
- require 'rake/contrib/rubyforgepublisher'
8
+
9
9
  require File.join(File.dirname(__FILE__), 'lib', 'active_resource', 'version')
10
10
 
11
11
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
@@ -64,7 +64,7 @@ spec = Gem::Specification.new do |s|
64
64
  s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
65
65
  end
66
66
 
67
- s.add_dependency('activesupport', '= 2.0.5' + PKG_BUILD)
67
+ s.add_dependency('activesupport', '= 2.1.0' + PKG_BUILD)
68
68
 
69
69
  s.require_path = 'lib'
70
70
  s.autorequire = 'active_resource'
@@ -114,8 +114,8 @@ end
114
114
 
115
115
  desc "Publish the beta gem"
116
116
  task :pgem => [:package] do
117
- Rake::SshFilePublisher.new("david@greed.loudthinking.com", "/u/sites/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
118
- `ssh david@greed.loudthinking.com '/u/sites/gems/gemupdate.sh'`
117
+ Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
118
+ `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
119
119
  end
120
120
 
121
121
  desc "Publish the API documentation"
@@ -14,12 +14,19 @@ module ActiveResource
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
- # class Person < ActiveResource::Base
18
- # self.site = "http://api.people.com:3000/"
19
- # end
17
+ # class Person < ActiveResource::Base
18
+ # self.site = "http://api.people.com:3000/"
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.
22
+ # you can now use Active Resource's lifecycles methods to manipulate resources. In the case where you already have
23
+ # an existing model with the same name as the desired RESTful resource you can set the +element_name+ value.
24
+ #
25
+ # class PersonResource < ActiveResource::Base
26
+ # self.site = "http://api.people.com:3000/"
27
+ # self.element_name = "person"
28
+ # end
29
+ #
23
30
  #
24
31
  # == Lifecycle methods
25
32
  #
@@ -27,18 +34,18 @@ module ActiveResource
27
34
  # from REST web services.
28
35
  #
29
36
  # ryan = Person.new(:first => 'Ryan', :last => 'Daigle')
30
- # ryan.save #=> true
31
- # ryan.id #=> 2
32
- # Person.exists?(ryan.id) #=> true
33
- # ryan.exists? #=> true
37
+ # ryan.save # => true
38
+ # ryan.id # => 2
39
+ # Person.exists?(ryan.id) # => true
40
+ # ryan.exists? # => true
34
41
  #
35
42
  # ryan = Person.find(1)
36
- # # => Resource holding our newly created Person object
43
+ # # Resource holding our newly created Person object
37
44
  #
38
45
  # ryan.first = 'Rizzle'
39
- # ryan.save #=> true
46
+ # ryan.save # => true
40
47
  #
41
- # ryan.destroy #=> true
48
+ # ryan.destroy # => true
42
49
  #
43
50
  # As you can see, these are very similar to Active Record's lifecycle methods for database records.
44
51
  # You can read more about each of these methods in their respective documentation.
@@ -72,29 +79,39 @@ module ActiveResource
72
79
  #
73
80
  # You can validate resources client side by overriding validation methods in the base class.
74
81
  #
75
- # class Person < ActiveResource::Base
76
- # self.site = "http://api.people.com:3000/"
77
- # protected
78
- # def validate
79
- # errors.add("last", "has invalid characters") unless last =~ /[a-zA-Z]*/
80
- # end
81
- # end
82
+ # class Person < ActiveResource::Base
83
+ # self.site = "http://api.people.com:3000/"
84
+ # protected
85
+ # def validate
86
+ # errors.add("last", "has invalid characters") unless last =~ /[a-zA-Z]*/
87
+ # end
88
+ # end
82
89
  #
83
90
  # See the ActiveResource::Validations documentation for more information.
84
91
  #
85
92
  # == Authentication
86
93
  #
87
94
  # Many REST APIs will require authentication, usually in the form of basic
88
- # HTTP authentication. Authentication can be specified by putting the credentials
89
- # in the +site+ variable of the Active Resource class you need to authenticate.
95
+ # HTTP authentication. Authentication can be specified by:
96
+ # * putting the credentials in the URL for the +site+ variable.
90
97
  #
91
- # class Person < ActiveResource::Base
92
- # self.site = "http://ryan:password@api.people.com:3000/"
93
- # end
98
+ # class Person < ActiveResource::Base
99
+ # self.site = "http://ryan:password@api.people.com:3000/"
100
+ # end
94
101
  #
102
+ # * defining +user+ and/or +password+ variables
103
+ #
104
+ # class Person < ActiveResource::Base
105
+ # self.site = "http://api.people.com:3000/"
106
+ # self.user = "ryan"
107
+ # self.password = "password"
108
+ # end
109
+ #
95
110
  # For obvious security reasons, it is probably best if such services are available
96
111
  # over HTTPS.
97
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 seperate user and password option.
98
115
  # == Errors & Validation
99
116
  #
100
117
  # Error handling and validation is handled in much the same manner as you're used to seeing in
@@ -108,18 +125,17 @@ module ActiveResource
108
125
  # exception.
109
126
  #
110
127
  # # GET http://api.people.com:3000/people/999.xml
111
- # ryan = Person.find(999) # => Raises ActiveResource::ResourceNotFound
112
- # # => Response = 404
128
+ # ryan = Person.find(999) # 404, raises ActiveResource::ResourceNotFound
113
129
  #
114
- # <tt>404</tt> is just one of the HTTP error response codes that ActiveResource will handle with its own exception. The
130
+ # <tt>404</tt> is just one of the HTTP error response codes that Active Resource will handle with its own exception. The
115
131
  # following HTTP response codes will also result in these exceptions:
116
132
  #
117
- # 200 - 399:: Valid response, no exception
118
- # 404:: ActiveResource::ResourceNotFound
119
- # 409:: ActiveResource::ResourceConflict
120
- # 422:: ActiveResource::ResourceInvalid (rescued by save as validation errors)
121
- # 401 - 499:: ActiveResource::ClientError
122
- # 500 - 599:: ActiveResource::ServerError
133
+ # * 200..399 - Valid response, no exception
134
+ # * 404 - ActiveResource::ResourceNotFound
135
+ # * 409 - ActiveResource::ResourceConflict
136
+ # * 422 - ActiveResource::ResourceInvalid (rescued by save as validation errors)
137
+ # * 401..499 - ActiveResource::ClientError
138
+ # * 500..599 - ActiveResource::ServerError
123
139
  #
124
140
  # These custom exceptions allow you to deal with resource errors more naturally and with more precision
125
141
  # rather than returning a general HTTP error. For example:
@@ -140,8 +156,8 @@ module ActiveResource
140
156
  # then fail (with a <tt>false</tt> return value) and the validation errors can be accessed on the resource in question.
141
157
  #
142
158
  # ryan = Person.find(1)
143
- # ryan.first #=> ''
144
- # ryan.save #=> false
159
+ # ryan.first # => ''
160
+ # ryan.save # => false
145
161
  #
146
162
  # # When
147
163
  # # PUT http://api.people.com:3000/people/1.xml
@@ -151,19 +167,57 @@ module ActiveResource
151
167
  # # <errors type="array"><error>First cannot be empty</error></errors>
152
168
  # #
153
169
  #
154
- # ryan.errors.invalid?(:first) #=> true
155
- # ryan.errors.full_messages #=> ['First cannot be empty']
170
+ # ryan.errors.invalid?(:first) # => true
171
+ # ryan.errors.full_messages # => ['First cannot be empty']
156
172
  #
157
173
  # Learn more about Active Resource's validation features in the ActiveResource::Validations documentation.
158
174
  #
175
+ # === Timeouts
176
+ #
177
+ # 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
179
+ # amount of time before Active Resource times out with the +timeout+ variable.
180
+ #
181
+ # class Person < ActiveResource::Base
182
+ # self.site = "http://api.people.com:3000/"
183
+ # self.timeout = 5
184
+ # end
185
+ #
186
+ # This sets the +timeout+ to 5 seconds. You can adjust the +timeout+ to a value suitable for the RESTful API
187
+ # you are accessing. It is recommended to set this to a reasonably low value to allow your Active Resource
188
+ # clients (especially if you are using Active Resource in a Rails application) to fail-fast (see
189
+ # http://en.wikipedia.org/wiki/Fail-fast) rather than cause cascading failures that could incapacitate your
190
+ # server.
191
+ #
192
+ # When a timeout occurs, an ActiveResource::TimeoutError is raised. You should rescue from
193
+ # ActiveResource::TimeoutError in your Active Resource method calls.
194
+ #
195
+ # Internally, Active Resource relies on Ruby's Net::HTTP library to make HTTP requests. Setting +timeout+
196
+ # sets the <tt>read_timeout</tt> of the internal Net::HTTP instance to the same value. The default
197
+ # <tt>read_timeout</tt> is 60 seconds on most Ruby implementations.
159
198
  class Base
160
199
  # The logger for diagnosing and tracing Active Resource calls.
161
200
  cattr_accessor :logger
162
201
 
163
202
  class << self
164
203
  # Gets the URI of the REST resources to map for this class. The site variable is required
165
- # ActiveResource's mapping to work.
204
+ # Active Resource's mapping to work.
166
205
  def site
206
+ # Not using superclass_delegating_reader because don't want subclasses to modify superclass instance
207
+ #
208
+ # With superclass_delegating_reader
209
+ #
210
+ # Parent.site = 'http://anonymous@test.com'
211
+ # Subclass.site # => 'http://anonymous@test.com'
212
+ # Subclass.site.user = 'david'
213
+ # Parent.site # => 'http://david@test.com'
214
+ #
215
+ # Without superclass_delegating_reader (expected behaviour)
216
+ #
217
+ # Parent.site = 'http://anonymous@test.com'
218
+ # Subclass.site # => 'http://anonymous@test.com'
219
+ # Subclass.site.user = 'david' # => TypeError: can't modify frozen object
220
+ #
167
221
  if defined?(@site)
168
222
  @site
169
223
  elsif superclass != Object && superclass.site
@@ -172,13 +226,51 @@ module ActiveResource
172
226
  end
173
227
 
174
228
  # Sets the URI of the REST resources to map for this class to the value in the +site+ argument.
175
- # The site variable is required ActiveResource's mapping to work.
229
+ # The site variable is required Active Resource's mapping to work.
176
230
  def site=(site)
177
231
  @connection = nil
178
- @site = site.nil? ? nil : create_site_uri_from(site)
232
+ if site.nil?
233
+ @site = nil
234
+ else
235
+ @site = create_site_uri_from(site)
236
+ @user = URI.decode(@site.user) if @site.user
237
+ @password = URI.decode(@site.password) if @site.password
238
+ end
239
+ end
240
+
241
+ # Gets the user for REST HTTP authentication.
242
+ def user
243
+ # Not using superclass_delegating_reader. See +site+ for explanation
244
+ if defined?(@user)
245
+ @user
246
+ elsif superclass != Object && superclass.user
247
+ superclass.user.dup.freeze
248
+ end
249
+ end
250
+
251
+ # Sets the user for REST HTTP authentication.
252
+ def user=(user)
253
+ @connection = nil
254
+ @user = user
179
255
  end
180
256
 
181
- # Sets the format that attributes are sent and received in from a mime type reference. Example:
257
+ # Gets the password for REST HTTP authentication.
258
+ def password
259
+ # Not using superclass_delegating_reader. See +site+ for explanation
260
+ if defined?(@password)
261
+ @password
262
+ elsif superclass != Object && superclass.password
263
+ superclass.password.dup.freeze
264
+ end
265
+ end
266
+
267
+ # Sets the password for REST HTTP authentication.
268
+ def password=(password)
269
+ @connection = nil
270
+ @password = password
271
+ end
272
+
273
+ # Sets the format that attributes are sent and received in from a mime type reference:
182
274
  #
183
275
  # Person.format = :json
184
276
  # Person.find(1) # => GET /people/1.json
@@ -186,7 +278,7 @@ module ActiveResource
186
278
  # Person.format = ActiveResource::Formats::XmlFormat
187
279
  # Person.find(1) # => GET /people/1.xml
188
280
  #
189
- # Default format is :xml.
281
+ # Default format is <tt>:xml</tt>.
190
282
  def format=(mime_type_reference_or_format)
191
283
  format = mime_type_reference_or_format.is_a?(Symbol) ?
192
284
  ActiveResource::Formats[mime_type_reference_or_format] : mime_type_reference_or_format
@@ -194,18 +286,36 @@ module ActiveResource
194
286
  write_inheritable_attribute("format", format)
195
287
  connection.format = format if site
196
288
  end
197
-
198
- # Returns the current format, default is ActiveResource::Formats::XmlFormat
289
+
290
+ # Returns the current format, default is ActiveResource::Formats::XmlFormat.
199
291
  def format # :nodoc:
200
292
  read_inheritable_attribute("format") || ActiveResource::Formats[:xml]
201
293
  end
202
294
 
295
+ # Sets the number of seconds after which requests to the REST API should time out.
296
+ def timeout=(timeout)
297
+ @connection = nil
298
+ @timeout = timeout
299
+ end
300
+
301
+ # Gets tthe number of seconds after which requests to the REST API should time out.
302
+ def timeout
303
+ if defined?(@timeout)
304
+ @timeout
305
+ elsif superclass != Object && superclass.timeout
306
+ superclass.timeout
307
+ end
308
+ end
309
+
203
310
  # An instance of ActiveResource::Connection that is the base connection to the remote service.
204
311
  # The +refresh+ parameter toggles whether or not the connection is refreshed at every request
205
312
  # or not (defaults to <tt>false</tt>).
206
313
  def connection(refresh = false)
207
314
  if defined?(@connection) || superclass == Object
208
315
  @connection = Connection.new(site, format) if refresh || @connection.nil?
316
+ @connection.user = user if user
317
+ @connection.password = password if password
318
+ @connection.timeout = timeout if timeout
209
319
  @connection
210
320
  else
211
321
  superclass.connection
@@ -266,9 +376,9 @@ module ActiveResource
266
376
  # will split from the prefix options.
267
377
  #
268
378
  # ==== Options
269
- # +prefix_options+:: A hash to add a prefix to the request for nested URL's (e.g., <tt>:account_id => 19</tt>
379
+ # +prefix_options+ - A hash to add a prefix to the request for nested URLs (e.g., <tt>:account_id => 19</tt>
270
380
  # would yield a URL like <tt>/accounts/19/purchases.xml</tt>).
271
- # +query_options+:: A hash to add items to the query string for the request.
381
+ # +query_options+ - A hash to add items to the query string for the request.
272
382
  #
273
383
  # ==== Examples
274
384
  # Post.element_path(1)
@@ -285,16 +395,16 @@ module ActiveResource
285
395
  #
286
396
  def element_path(id, prefix_options = {}, query_options = nil)
287
397
  prefix_options, query_options = split_options(prefix_options) if query_options.nil?
288
- "#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
398
+ "#{prefix(prefix_options)}#{collection_name}/#{id}.#{format.extension}#{query_string(query_options)}"
289
399
  end
290
400
 
291
401
  # Gets the collection path for the REST resources. If the +query_options+ parameter is omitted, Rails
292
402
  # will split from the +prefix_options+.
293
403
  #
294
404
  # ==== Options
295
- # +prefix_options+:: A hash to add a prefix to the request for nested URL's (e.g., <tt>:account_id => 19</tt>
296
- # would yield a URL like <tt>/accounts/19/purchases.xml</tt>).
297
- # +query_options+:: A hash to add items to the query string for the request.
405
+ # * +prefix_options+ - A hash to add a prefix to the request for nested URL's (e.g., <tt>:account_id => 19</tt>
406
+ # would yield a URL like <tt>/accounts/19/purchases.xml</tt>).
407
+ # * +query_options+ - A hash to add items to the query string for the request.
298
408
  #
299
409
  # ==== Examples
300
410
  # Post.collection_path
@@ -330,39 +440,34 @@ module ActiveResource
330
440
  # ==== Examples
331
441
  # Person.create(:name => 'Jeremy', :email => 'myname@nospam.com', :enabled => true)
332
442
  # my_person = Person.find(:first)
333
- # my_person.email
334
- # # => myname@nospam.com
443
+ # my_person.email # => myname@nospam.com
335
444
  #
336
445
  # dhh = Person.create(:name => 'David', :email => 'dhh@nospam.com', :enabled => true)
337
- # dhh.valid?
338
- # # => true
339
- # dhh.new?
340
- # # => false
446
+ # dhh.valid? # => true
447
+ # dhh.new? # => false
341
448
  #
342
449
  # # We'll assume that there's a validation that requires the name attribute
343
450
  # that_guy = Person.create(:name => '', :email => 'thatguy@nospam.com', :enabled => true)
344
- # that_guy.valid?
345
- # # => false
346
- # that_guy.new?
347
- # # => true
348
- #
451
+ # that_guy.valid? # => false
452
+ # that_guy.new? # => true
349
453
  def create(attributes = {})
350
454
  returning(self.new(attributes)) { |res| res.save }
351
455
  end
352
456
 
353
- # Core method for finding resources. Used similarly to Active Record's find method.
457
+ # Core method for finding resources. Used similarly to Active Record's +find+ method.
354
458
  #
355
459
  # ==== Arguments
356
460
  # The first argument is considered to be the scope of the query. That is, how many
357
461
  # resources are returned from the request. It can be one of the following.
358
462
  #
359
- # +:one+:: Returns a single resource.
360
- # +:first+:: Returns the first resource found.
361
- # +:all+:: Returns every resource that matches the request.
463
+ # * <tt>:one</tt> - Returns a single resource.
464
+ # * <tt>:first</tt> - Returns the first resource found.
465
+ # * <tt>:all</tt> - Returns every resource that matches the request.
362
466
  #
363
467
  # ==== Options
364
- # +from+:: Sets the path or custom method that resources will be fetched from.
365
- # +params+:: Sets query and prefix (nested URL) parameters.
468
+ #
469
+ # * <tt>:from</tt> - Sets the path or custom method that resources will be fetched from.
470
+ # * <tt>:params</tt> - Sets query and prefix (nested URL) parameters.
366
471
  #
367
472
  # ==== Examples
368
473
  # Person.find(1)
@@ -409,19 +514,14 @@ module ActiveResource
409
514
  # All options specify prefix and query parameters.
410
515
  #
411
516
  # ==== Examples
412
- # Event.delete(2)
413
- # # => DELETE /events/2
517
+ # Event.delete(2) # sends DELETE /events/2
414
518
  #
415
519
  # Event.create(:name => 'Free Concert', :location => 'Community Center')
416
- # my_event = Event.find(:first)
417
- # # => Events (id: 7)
418
- # Event.delete(my_event.id)
419
- # # => DELETE /events/7
520
+ # my_event = Event.find(:first) # let's assume this is event with ID 7
521
+ # Event.delete(my_event.id) # sends DELETE /events/7
420
522
  #
421
523
  # # Let's assume a request to events/5/cancel.xml
422
- # Event.delete(params[:id])
423
- # # => DELETE /events/5
424
- #
524
+ # Event.delete(params[:id]) # sends DELETE /events/5
425
525
  def delete(id, options = {})
426
526
  connection.delete(element_path(id, options))
427
527
  end
@@ -430,13 +530,17 @@ module ActiveResource
430
530
  #
431
531
  # ==== Examples
432
532
  # Note.create(:title => 'Hello, world.', :body => 'Nothing more for now...')
433
- # Note.exists?(1)
434
- # # => true
533
+ # Note.exists?(1) # => true
435
534
  #
436
- # Note.exists(1349)
437
- # # => false
535
+ # Note.exists(1349) # => false
438
536
  def exists?(id, options = {})
439
- id && !find_single(id, options).nil?
537
+ if id
538
+ prefix_options, query_options = split_options(options[:params])
539
+ path = element_path(id, prefix_options, query_options)
540
+ response = connection.head(path, headers)
541
+ response.code == 200
542
+ end
543
+ # id && !find_single(id, options).nil?
440
544
  rescue ActiveResource::ResourceNotFound
441
545
  false
442
546
  end
@@ -518,7 +622,7 @@ module ActiveResource
518
622
  attr_accessor :attributes #:nodoc:
519
623
  attr_accessor :prefix_options #:nodoc:
520
624
 
521
- # Constructor method for new resources; the optional +attributes+ parameter takes a +Hash+
625
+ # Constructor method for new resources; the optional +attributes+ parameter takes a hash
522
626
  # of attributes for the new resource.
523
627
  #
524
628
  # ==== Examples
@@ -535,20 +639,53 @@ module ActiveResource
535
639
  load(attributes)
536
640
  end
537
641
 
642
+ # Returns a clone of the resource that hasn't been assigned an +id+ yet and
643
+ # is treated as a new resource.
644
+ #
645
+ # ryan = Person.find(1)
646
+ # not_ryan = ryan.clone
647
+ # not_ryan.new? # => true
648
+ #
649
+ # Any active resource member attributes will NOT be cloned, though all other
650
+ # attributes are. This is to prevent the conflict between any +prefix_options+
651
+ # that refer to the original parent resource and the newly cloned parent
652
+ # resource that does not exist.
653
+ #
654
+ # ryan = Person.find(1)
655
+ # ryan.address = StreetAddress.find(1, :person_id => ryan.id)
656
+ # ryan.hash = {:not => "an ARes instance"}
657
+ #
658
+ # not_ryan = ryan.clone
659
+ # not_ryan.new? # => true
660
+ # not_ryan.address # => NoMethodError
661
+ # not_ryan.hash # => {:not => "an ARes instance"}
662
+ def clone
663
+ # Clone all attributes except the pk and any nested ARes
664
+ cloned = attributes.reject {|k,v| k == self.class.primary_key || v.is_a?(ActiveResource::Base)}.inject({}) do |attrs, (k, v)|
665
+ attrs[k] = v.clone
666
+ attrs
667
+ end
668
+ # Form the new resource - bypass initialize of resource with 'new' as that will call 'load' which
669
+ # attempts to convert hashes into member objects and arrays into collections of objects. We want
670
+ # the raw objects to be cloned so we bypass load by directly setting the attributes hash.
671
+ resource = self.class.new({})
672
+ resource.prefix_options = self.prefix_options
673
+ resource.send :instance_variable_set, '@attributes', cloned
674
+ resource
675
+ end
676
+
677
+
538
678
  # A method to determine if the resource a new object (i.e., it has not been POSTed to the remote service yet).
539
679
  #
540
680
  # ==== Examples
541
681
  # not_new = Computer.create(:brand => 'Apple', :make => 'MacBook', :vendor => 'MacMall')
542
- # not_new.new?
543
- # # => false
682
+ # not_new.new? # => false
544
683
  #
545
684
  # is_new = Computer.new(:brand => 'IBM', :make => 'Thinkpad', :vendor => 'IBM')
546
- # is_new.new?
547
- # # => true
685
+ # is_new.new? # => true
548
686
  #
549
687
  # is_new.save
550
- # is_new.new?
551
- # # => false
688
+ # is_new.new? # => false
552
689
  #
553
690
  def new?
554
691
  id.nil?
@@ -564,13 +701,13 @@ module ActiveResource
564
701
  attributes[self.class.primary_key] = id
565
702
  end
566
703
 
567
- # Allows ActiveResource objects to be used as parameters in ActionPack URL generation.
704
+ # Allows Active Resource objects to be used as parameters in Action Pack URL generation.
568
705
  def to_param
569
706
  id && id.to_s
570
707
  end
571
708
 
572
709
  # Test for equality. Resource are equal if and only if +other+ is the same object or
573
- # is an instance of the same class, is not +new?+, and has the same +id+.
710
+ # is an instance of the same class, is not <tt>new?</tt>, and has the same +id+.
574
711
  #
575
712
  # ==== Examples
576
713
  # ryan = Person.create(:name => 'Ryan')
@@ -611,17 +748,13 @@ module ActiveResource
611
748
  # ==== Examples
612
749
  # my_invoice = Invoice.create(:customer => 'That Company')
613
750
  # next_invoice = my_invoice.dup
614
- # next_invoice.new?
615
- # # => true
751
+ # next_invoice.new? # => true
616
752
  #
617
753
  # next_invoice.save
618
- # next_invoice == my_invoice
619
- # # => false (different id attributes)
754
+ # next_invoice == my_invoice # => false (different id attributes)
620
755
  #
621
- # my_invoice.customer
622
- # # => That Company
623
- # next_invoice.customer
624
- # # => That Company
756
+ # my_invoice.customer # => That Company
757
+ # next_invoice.customer # => That Company
625
758
  def dup
626
759
  returning self.class.new do |resource|
627
760
  resource.attributes = @attributes
@@ -636,16 +769,12 @@ module ActiveResource
636
769
  #
637
770
  # ==== Examples
638
771
  # my_company = Company.new(:name => 'RoleModel Software', :owner => 'Ken Auer', :size => 2)
639
- # my_company.new?
640
- # # => true
641
- # my_company.save
642
- # # => POST /companies/ (create)
772
+ # my_company.new? # => true
773
+ # my_company.save # sends POST /companies/ (create)
643
774
  #
644
- # my_company.new?
645
- # # => false
775
+ # my_company.new? # => false
646
776
  # my_company.size = 10
647
- # my_company.save
648
- # # => PUT /companies/1 (update)
777
+ # my_company.save # sends PUT /companies/1 (update)
649
778
  def save
650
779
  new? ? create : update
651
780
  end
@@ -656,20 +785,17 @@ module ActiveResource
656
785
  # my_id = 3
657
786
  # my_person = Person.find(my_id)
658
787
  # my_person.destroy
659
- # Person.find(my_id)
660
- # # => 404 (Resource Not Found)
788
+ # Person.find(my_id) # 404 (Resource Not Found)
661
789
  #
662
790
  # new_person = Person.create(:name => 'James')
663
- # new_id = new_person.id
664
- # # => 7
791
+ # new_id = new_person.id # => 7
665
792
  # new_person.destroy
666
- # Person.find(new_id)
667
- # # => 404 (Resource Not Found)
793
+ # Person.find(new_id) # 404 (Resource Not Found)
668
794
  def destroy
669
795
  connection.delete(element_path, self.class.headers)
670
796
  end
671
797
 
672
- # Evaluates to <tt>true</tt> if this resource is not +new?+ and is
798
+ # Evaluates to <tt>true</tt> if this resource is not <tt>new?</tt> and is
673
799
  # found on the remote service. Using this method, you can check for
674
800
  # resources that may have been deleted between the object's instantiation
675
801
  # and actions on it.
@@ -677,19 +803,16 @@ module ActiveResource
677
803
  # ==== Examples
678
804
  # Person.create(:name => 'Theodore Roosevelt')
679
805
  # that_guy = Person.find(:first)
680
- # that_guy.exists?
681
- # # => true
806
+ # that_guy.exists? # => true
682
807
  #
683
808
  # that_lady = Person.new(:name => 'Paul Bean')
684
- # that_lady.exists?
685
- # # => false
809
+ # that_lady.exists? # => false
686
810
  #
687
811
  # guys_id = that_guy.id
688
812
  # Person.delete(guys_id)
689
- # that_guy.exists?
690
- # # => false
813
+ # that_guy.exists? # => false
691
814
  def exists?
692
- !new? && self.class.exists?(id, :params => prefix_options)
815
+ !new? && self.class.exists?(to_param, :params => prefix_options)
693
816
  end
694
817
 
695
818
  # A method to convert the the resource to an XML string.
@@ -697,13 +820,13 @@ module ActiveResource
697
820
  # ==== Options
698
821
  # The +options+ parameter is handed off to the +to_xml+ method on each
699
822
  # attribute, so it has the same options as the +to_xml+ methods in
700
- # ActiveSupport.
823
+ # Active Support.
701
824
  #
702
- # indent:: Set the indent level for the XML output (default is +2+).
703
- # dasherize:: Boolean option to determine whether or not element names should
704
- # replace underscores with dashes (default is <tt>false</tt>).
705
- # skip_instruct:: Toggle skipping the +instruct!+ call on the XML builder
706
- # that generates the XML declaration (default is <tt>false</tt>).
825
+ # * <tt>:indent</tt> - Set the indent level for the XML output (default is +2+).
826
+ # * <tt>:dasherize</tt> - Boolean option to determine whether or not element names should
827
+ # replace underscores with dashes (default is <tt>false</tt>).
828
+ # * <tt>:skip_instruct</tt> - Toggle skipping the +instruct!+ call on the XML builder
829
+ # that generates the XML declaration (default is <tt>false</tt>).
707
830
  #
708
831
  # ==== Examples
709
832
  # my_group = SubsidiaryGroup.find(:first)
@@ -725,30 +848,26 @@ module ActiveResource
725
848
  #
726
849
  # ==== Examples
727
850
  # my_branch = Branch.find(:first)
728
- # my_branch.name
729
- # # => Wislon Raod
851
+ # my_branch.name # => "Wislon Raod"
730
852
  #
731
853
  # # Another client fixes the typo...
732
854
  #
733
- # my_branch.name
734
- # # => Wislon Raod
855
+ # my_branch.name # => "Wislon Raod"
735
856
  # my_branch.reload
736
- # my_branch.name
737
- # # => Wilson Road
857
+ # my_branch.name # => "Wilson Road"
738
858
  def reload
739
- self.load(self.class.find(id, :params => @prefix_options).attributes)
859
+ self.load(self.class.find(to_param, :params => @prefix_options).attributes)
740
860
  end
741
861
 
742
862
  # A method to manually load attributes from a hash. Recursively loads collections of
743
- # resources. This method is called in initialize and create when a +Hash+ of attributes
863
+ # resources. This method is called in +initialize+ and +create+ when a hash of attributes
744
864
  # is provided.
745
865
  #
746
866
  # ==== Examples
747
867
  # my_attrs = {:name => 'J&J Textiles', :industry => 'Cloth and textiles'}
748
868
  #
749
869
  # the_supplier = Supplier.find(:first)
750
- # the_supplier.name
751
- # # => 'J&M Textiles'
870
+ # the_supplier.name # => 'J&M Textiles'
752
871
  # the_supplier.load(my_attrs)
753
872
  # the_supplier.name('J&J Textiles')
754
873
  #
@@ -779,10 +898,10 @@ module ActiveResource
779
898
  self
780
899
  end
781
900
 
782
- # For checking respond_to? without searching the attributes (which is faster).
901
+ # For checking <tt>respond_to?</tt> without searching the attributes (which is faster).
783
902
  alias_method :respond_to_without_attributes?, :respond_to?
784
903
 
785
- # A method to determine if an object responds to a message (e.g., a method call). In Active Resource, a +Person+ object with a
904
+ # A method to determine if an object responds to a message (e.g., a method call). In Active Resource, a Person object with a
786
905
  # +name+ attribute can answer <tt>true</tt> to <tt>my_person.respond_to?("name")</tt>, <tt>my_person.respond_to?("name=")</tt>, and
787
906
  # <tt>my_person.respond_to?("name?")</tt>.
788
907
  def respond_to?(method, include_priv = false)
@@ -832,7 +951,7 @@ module ActiveResource
832
951
  end
833
952
 
834
953
  def element_path(options = nil)
835
- self.class.element_path(id, options || prefix_options)
954
+ self.class.element_path(to_param, options || prefix_options)
836
955
  end
837
956
 
838
957
  def collection_path(options = nil)