activeresource 2.0.1
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 +216 -0
- data/README +165 -0
- data/Rakefile +133 -0
- data/lib/active_resource.rb +47 -0
- data/lib/active_resource/base.rb +872 -0
- data/lib/active_resource/connection.rb +157 -0
- data/lib/active_resource/custom_methods.rb +105 -0
- data/lib/active_resource/formats.rb +14 -0
- data/lib/active_resource/formats/json_format.rb +23 -0
- data/lib/active_resource/formats/xml_format.rb +34 -0
- data/lib/active_resource/http_mock.rb +136 -0
- data/lib/active_resource/validations.rb +288 -0
- data/lib/active_resource/version.rb +9 -0
- data/lib/activeresource.rb +1 -0
- data/test/abstract_unit.rb +10 -0
- data/test/authorization_test.rb +82 -0
- data/test/base/custom_methods_test.rb +96 -0
- data/test/base/equality_test.rb +43 -0
- data/test/base/load_test.rb +111 -0
- data/test/base_errors_test.rb +48 -0
- data/test/base_test.rb +454 -0
- data/test/base_test.rb.rej +17 -0
- data/test/connection_test.rb +161 -0
- data/test/debug.log +5477 -0
- data/test/fixtures/beast.rb +14 -0
- data/test/fixtures/person.rb +3 -0
- data/test/fixtures/street_address.rb +4 -0
- data/test/format_test.rb +42 -0
- data/test/setter_trap.rb +27 -0
- metadata +87 -0
@@ -0,0 +1,288 @@
|
|
1
|
+
module ActiveResource
|
2
|
+
class ResourceInvalid < ClientError #:nodoc:
|
3
|
+
end
|
4
|
+
|
5
|
+
# Active Resource validation is reported to and from this object, which is used by Base#save
|
6
|
+
# to determine whether the object in a valid state to be saved. See usage example in Validations.
|
7
|
+
class Errors
|
8
|
+
include Enumerable
|
9
|
+
attr_reader :errors
|
10
|
+
|
11
|
+
delegate :empty?, :to => :errors
|
12
|
+
|
13
|
+
def initialize(base) # :nodoc:
|
14
|
+
@base, @errors = base, {}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Add an error to the base Active Resource object rather than an attribute.
|
18
|
+
#
|
19
|
+
# ==== Examples
|
20
|
+
# my_folder = Folder.find(1)
|
21
|
+
# my_folder.errors.add_to_base("You can't edit an existing folder")
|
22
|
+
# my_folder.errors.on_base
|
23
|
+
# # => "You can't edit an existing folder"
|
24
|
+
#
|
25
|
+
# my_folder.errors.add_to_base("This folder has been tagged as frozen")
|
26
|
+
# my_folder.valid?
|
27
|
+
# # => false
|
28
|
+
# my_folder.errors.on_base
|
29
|
+
# # => ["You can't edit an existing folder", "This folder has been tagged as frozen"]
|
30
|
+
#
|
31
|
+
def add_to_base(msg)
|
32
|
+
add(:base, msg)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Adds an error to an Active Resource object's attribute (named for the +attribute+ parameter)
|
36
|
+
# with the error message in +msg+.
|
37
|
+
#
|
38
|
+
# ==== Examples
|
39
|
+
# my_resource = Node.find(1)
|
40
|
+
# my_resource.errors.add('name', 'can not be "base"') if my_resource.name == 'base'
|
41
|
+
# my_resource.errors.on('name')
|
42
|
+
# # => 'can not be "base"!'
|
43
|
+
#
|
44
|
+
# my_resource.errors.add('desc', 'can not be blank') if my_resource.desc == ''
|
45
|
+
# my_resource.valid?
|
46
|
+
# # => false
|
47
|
+
# my_resource.errors.on('desc')
|
48
|
+
# # => 'can not be blank!'
|
49
|
+
#
|
50
|
+
def add(attribute, msg)
|
51
|
+
@errors[attribute.to_s] = [] if @errors[attribute.to_s].nil?
|
52
|
+
@errors[attribute.to_s] << msg
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns true if the specified +attribute+ has errors associated with it.
|
56
|
+
#
|
57
|
+
# ==== Examples
|
58
|
+
# my_resource = Disk.find(1)
|
59
|
+
# my_resource.errors.add('location', 'must be Main') unless my_resource.location == 'Main'
|
60
|
+
# my_resource.errors.on('location')
|
61
|
+
# # => 'must be Main!'
|
62
|
+
#
|
63
|
+
# my_resource.errors.invalid?('location')
|
64
|
+
# # => true
|
65
|
+
# my_resource.errors.invalid?('name')
|
66
|
+
# # => false
|
67
|
+
def invalid?(attribute)
|
68
|
+
!@errors[attribute.to_s].nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
# A method to return the errors associated with +attribute+, which returns nil, if no errors are
|
72
|
+
# associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+,
|
73
|
+
# or an array of error messages if more than one error is associated with the specified +attribute+.
|
74
|
+
#
|
75
|
+
# ==== Examples
|
76
|
+
# my_person = Person.new(params[:person])
|
77
|
+
# my_person.errors.on('login')
|
78
|
+
# # => nil
|
79
|
+
#
|
80
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
81
|
+
# my_person.errors.on('login')
|
82
|
+
# # => 'can not be empty'
|
83
|
+
#
|
84
|
+
# my_person.errors.add('login', 'can not be longer than 10 characters') if my_person.login.length > 10
|
85
|
+
# my_person.errors.on('login')
|
86
|
+
# # => ['can not be empty', 'can not be longer than 10 characters']
|
87
|
+
def on(attribute)
|
88
|
+
errors = @errors[attribute.to_s]
|
89
|
+
return nil if errors.nil?
|
90
|
+
errors.size == 1 ? errors.first : errors
|
91
|
+
end
|
92
|
+
|
93
|
+
alias :[] :on
|
94
|
+
|
95
|
+
# A method to return errors assigned to +base+ object through add_to_base, which returns nil, if no errors are
|
96
|
+
# associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+,
|
97
|
+
# or an array of error messages if more than one error is associated with the specified +attribute+.
|
98
|
+
#
|
99
|
+
# ==== Examples
|
100
|
+
# my_account = Account.find(1)
|
101
|
+
# my_account.errors.on_base
|
102
|
+
# # => nil
|
103
|
+
#
|
104
|
+
# my_account.errors.add_to_base("This account is frozen")
|
105
|
+
# my_account.errors.on_base
|
106
|
+
# # => "This account is frozen"
|
107
|
+
#
|
108
|
+
# my_account.errors.add_to_base("This account has been closed")
|
109
|
+
# my_account.errors.on_base
|
110
|
+
# # => ["This account is frozen", "This account has been closed"]
|
111
|
+
#
|
112
|
+
def on_base
|
113
|
+
on(:base)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Yields each attribute and associated message per error added.
|
117
|
+
#
|
118
|
+
# ==== Examples
|
119
|
+
# my_person = Person.new(params[:person])
|
120
|
+
#
|
121
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
122
|
+
# my_person.errors.add('password', 'can not be empty') if my_person.password == ''
|
123
|
+
# messages = ''
|
124
|
+
# my_person.errors.each {|attr, msg| messages += attr.humanize + " " + msg + "<br />"}
|
125
|
+
# messages
|
126
|
+
# # => "Login can not be empty<br />Password can not be empty<br />"
|
127
|
+
#
|
128
|
+
def each
|
129
|
+
@errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } }
|
130
|
+
end
|
131
|
+
|
132
|
+
# Yields each full error message added. So Person.errors.add("first_name", "can't be empty") will be returned
|
133
|
+
# through iteration as "First name can't be empty".
|
134
|
+
#
|
135
|
+
# ==== Examples
|
136
|
+
# my_person = Person.new(params[:person])
|
137
|
+
#
|
138
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
139
|
+
# my_person.errors.add('password', 'can not be empty') if my_person.password == ''
|
140
|
+
# messages = ''
|
141
|
+
# my_person.errors.each_full {|msg| messages += msg + "<br/>"}
|
142
|
+
# messages
|
143
|
+
# # => "Login can not be empty<br />Password can not be empty<br />"
|
144
|
+
#
|
145
|
+
def each_full
|
146
|
+
full_messages.each { |msg| yield msg }
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns all the full error messages in an array.
|
150
|
+
#
|
151
|
+
# ==== Examples
|
152
|
+
# my_person = Person.new(params[:person])
|
153
|
+
#
|
154
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
155
|
+
# my_person.errors.add('password', 'can not be empty') if my_person.password == ''
|
156
|
+
# messages = ''
|
157
|
+
# my_person.errors.full_messages.each {|msg| messages += msg + "<br/>"}
|
158
|
+
# messages
|
159
|
+
# # => "Login can not be empty<br />Password can not be empty<br />"
|
160
|
+
#
|
161
|
+
def full_messages
|
162
|
+
full_messages = []
|
163
|
+
|
164
|
+
@errors.each_key do |attr|
|
165
|
+
@errors[attr].each do |msg|
|
166
|
+
next if msg.nil?
|
167
|
+
|
168
|
+
if attr == "base"
|
169
|
+
full_messages << msg
|
170
|
+
else
|
171
|
+
full_messages << [attr.humanize, msg].join(' ')
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
full_messages
|
176
|
+
end
|
177
|
+
|
178
|
+
def clear
|
179
|
+
@errors = {}
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns the total number of errors added. Two errors added to the same attribute will be counted as such
|
183
|
+
# with this as well.
|
184
|
+
#
|
185
|
+
# ==== Examples
|
186
|
+
# my_person = Person.new(params[:person])
|
187
|
+
# my_person.errors.size
|
188
|
+
# # => 0
|
189
|
+
#
|
190
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
191
|
+
# my_person.errors.add('password', 'can not be empty') if my_person.password == ''
|
192
|
+
# my_person.error.size
|
193
|
+
# # => 2
|
194
|
+
#
|
195
|
+
def size
|
196
|
+
@errors.values.inject(0) { |error_count, attribute| error_count + attribute.size }
|
197
|
+
end
|
198
|
+
|
199
|
+
alias_method :count, :size
|
200
|
+
alias_method :length, :size
|
201
|
+
|
202
|
+
# Grabs errors from the XML response.
|
203
|
+
def from_xml(xml)
|
204
|
+
clear
|
205
|
+
humanized_attributes = @base.attributes.keys.inject({}) { |h, attr_name| h.update(attr_name.humanize => attr_name) }
|
206
|
+
messages = Hash.from_xml(xml)['errors']['error'] rescue []
|
207
|
+
messages.each do |message|
|
208
|
+
attr_message = humanized_attributes.keys.detect do |attr_name|
|
209
|
+
if message[0, attr_name.size + 1] == "#{attr_name} "
|
210
|
+
add humanized_attributes[attr_name], message[(attr_name.size + 1)..-1]
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
add_to_base message if attr_message.nil?
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Module to allow validation of ActiveResource objects, which creates an Errors instance for every resource.
|
220
|
+
# Methods are implemented by overriding +Base#validate+ or its variants Each of these methods can inspect
|
221
|
+
# the state of the object, which usually means ensuring that a number of attributes have a certain value
|
222
|
+
# (such as not empty, within a given range, matching a certain regular expression and so on).
|
223
|
+
#
|
224
|
+
# ==== Example
|
225
|
+
#
|
226
|
+
# class Person < ActiveResource::Base
|
227
|
+
# self.site = "http://www.localhost.com:3000/"
|
228
|
+
# protected
|
229
|
+
# def validate
|
230
|
+
# errors.add_on_empty %w( first_name last_name )
|
231
|
+
# errors.add("phone_number", "has invalid format") unless phone_number =~ /[0-9]*/
|
232
|
+
# end
|
233
|
+
#
|
234
|
+
# def validate_on_create # is only run the first time a new object is saved
|
235
|
+
# unless valid_member?(self)
|
236
|
+
# errors.add("membership_discount", "has expired")
|
237
|
+
# end
|
238
|
+
# end
|
239
|
+
#
|
240
|
+
# def validate_on_update
|
241
|
+
# errors.add_to_base("No changes have occurred") if unchanged_attributes?
|
242
|
+
# end
|
243
|
+
# end
|
244
|
+
#
|
245
|
+
# person = Person.new("first_name" => "Jim", "phone_number" => "I will not tell you.")
|
246
|
+
# person.save # => false (and doesn't do the save)
|
247
|
+
# person.errors.empty? # => false
|
248
|
+
# person.errors.count # => 2
|
249
|
+
# person.errors.on "last_name" # => "can't be empty"
|
250
|
+
# person.attributes = { "last_name" => "Halpert", "phone_number" => "555-5555" }
|
251
|
+
# person.save # => true (and person is now saved to the remote service)
|
252
|
+
#
|
253
|
+
module Validations
|
254
|
+
def self.included(base) # :nodoc:
|
255
|
+
base.class_eval do
|
256
|
+
alias_method_chain :save, :validation
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# Validate a resource and save (POST) it to the remote web service.
|
261
|
+
def save_with_validation
|
262
|
+
save_without_validation
|
263
|
+
true
|
264
|
+
rescue ResourceInvalid => error
|
265
|
+
errors.from_xml(error.response.body)
|
266
|
+
false
|
267
|
+
end
|
268
|
+
|
269
|
+
# Checks for errors on an object (i.e., is resource.errors empty?).
|
270
|
+
#
|
271
|
+
# ==== Examples
|
272
|
+
# my_person = Person.create(params[:person])
|
273
|
+
# my_person.valid?
|
274
|
+
# # => true
|
275
|
+
#
|
276
|
+
# my_person.errors.add('login', 'can not be empty') if my_person.login == ''
|
277
|
+
# my_person.valid?
|
278
|
+
# # => false
|
279
|
+
def valid?
|
280
|
+
errors.empty?
|
281
|
+
end
|
282
|
+
|
283
|
+
# Returns the Errors object that holds all information about attribute error messages.
|
284
|
+
def errors
|
285
|
+
@errors ||= Errors.new(self)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_resource'
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
$:.unshift "#{File.dirname(__FILE__)}/../lib"
|
4
|
+
require 'active_resource'
|
5
|
+
require 'active_resource/http_mock'
|
6
|
+
|
7
|
+
$:.unshift "#{File.dirname(__FILE__)}/../test"
|
8
|
+
require 'setter_trap'
|
9
|
+
|
10
|
+
ActiveResource::Base.logger = Logger.new("#{File.dirname(__FILE__)}/debug.log")
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/abstract_unit"
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
class AuthorizationTest < Test::Unit::TestCase
|
5
|
+
Response = Struct.new(:code)
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@conn = ActiveResource::Connection.new('http://localhost')
|
9
|
+
@matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
|
10
|
+
@david = { :id => 2, :name => 'David' }.to_xml(:root => 'person')
|
11
|
+
@authenticated_conn = ActiveResource::Connection.new("http://david:test123@localhost")
|
12
|
+
@authorization_request_header = { 'Authorization' => 'Basic ZGF2aWQ6dGVzdDEyMw==' }
|
13
|
+
|
14
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
15
|
+
mock.get "/people/2.xml", @authorization_request_header, @david
|
16
|
+
mock.put "/people/2.xml", @authorization_request_header, nil, 204
|
17
|
+
mock.delete "/people/2.xml", @authorization_request_header, nil, 200
|
18
|
+
mock.post "/people/2/addresses.xml", @authorization_request_header, nil, 201, 'Location' => '/people/1/addresses/5'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_authorization_header
|
23
|
+
authorization_header = @authenticated_conn.send!(:authorization_header)
|
24
|
+
assert_equal @authorization_request_header['Authorization'], authorization_header['Authorization']
|
25
|
+
authorization = authorization_header["Authorization"].to_s.split
|
26
|
+
|
27
|
+
assert_equal "Basic", authorization[0]
|
28
|
+
assert_equal ["david", "test123"], Base64.decode64(authorization[1]).split(":")[0..1]
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_authorization_header_with_username_but_no_password
|
32
|
+
@conn = ActiveResource::Connection.new("http://david:@localhost")
|
33
|
+
authorization_header = @conn.send!(:authorization_header)
|
34
|
+
authorization = authorization_header["Authorization"].to_s.split
|
35
|
+
|
36
|
+
assert_equal "Basic", authorization[0]
|
37
|
+
assert_equal ["david"], Base64.decode64(authorization[1]).split(":")[0..1]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_authorization_header_with_password_but_no_username
|
41
|
+
@conn = ActiveResource::Connection.new("http://:test123@localhost")
|
42
|
+
authorization_header = @conn.send!(:authorization_header)
|
43
|
+
authorization = authorization_header["Authorization"].to_s.split
|
44
|
+
|
45
|
+
assert_equal "Basic", authorization[0]
|
46
|
+
assert_equal ["", "test123"], Base64.decode64(authorization[1]).split(":")[0..1]
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_get
|
50
|
+
david = @authenticated_conn.get("/people/2.xml")
|
51
|
+
assert_equal "David", david["name"]
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_post
|
55
|
+
response = @authenticated_conn.post("/people/2/addresses.xml")
|
56
|
+
assert_equal "/people/1/addresses/5", response["Location"]
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_put
|
60
|
+
response = @authenticated_conn.put("/people/2.xml")
|
61
|
+
assert_equal 204, response.code
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_delete
|
65
|
+
response = @authenticated_conn.delete("/people/2.xml")
|
66
|
+
assert_equal 200, response.code
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_raises_invalid_request_on_unauthorized_requests
|
70
|
+
assert_raises(ActiveResource::InvalidRequestError) { @conn.post("/people/2.xml") }
|
71
|
+
assert_raises(ActiveResource::InvalidRequestError) { @conn.post("/people/2/addresses.xml") }
|
72
|
+
assert_raises(ActiveResource::InvalidRequestError) { @conn.put("/people/2.xml") }
|
73
|
+
assert_raises(ActiveResource::InvalidRequestError) { @conn.delete("/people/2.xml") }
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
def assert_response_raises(klass, code)
|
78
|
+
assert_raise(klass, "Expected response code #{code} to raise #{klass}") do
|
79
|
+
@conn.send!(:handle_response, Response.new(code))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../abstract_unit"
|
2
|
+
require "#{File.dirname(__FILE__)}/../fixtures/person"
|
3
|
+
require "#{File.dirname(__FILE__)}/../fixtures/street_address"
|
4
|
+
|
5
|
+
class CustomMethodsTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@matz = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person')
|
8
|
+
@matz_deep = { :id => 1, :name => 'Matz', :other => 'other' }.to_xml(:root => 'person')
|
9
|
+
@matz_array = [{ :id => 1, :name => 'Matz' }].to_xml(:root => 'people')
|
10
|
+
@ryan = { :name => 'Ryan' }.to_xml(:root => 'person')
|
11
|
+
@addy = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address')
|
12
|
+
@addy_deep = { :id => 1, :street => '12345 Street', :zip => "27519" }.to_xml(:root => 'address')
|
13
|
+
@default_request_headers = { 'Content-Type' => 'application/xml' }
|
14
|
+
|
15
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
16
|
+
mock.get "/people/1.xml", {}, @matz
|
17
|
+
mock.get "/people/1/shallow.xml", {}, @matz
|
18
|
+
mock.get "/people/1/deep.xml", {}, @matz_deep
|
19
|
+
mock.get "/people/retrieve.xml?name=Matz", {}, @matz_array
|
20
|
+
mock.get "/people/managers.xml", {}, @matz_array
|
21
|
+
mock.post "/people/hire.xml?name=Matz", {}, nil, 201
|
22
|
+
mock.put "/people/1/promote.xml?position=Manager", {}, nil, 204
|
23
|
+
mock.put "/people/promote.xml?name=Matz", {}, nil, 204, {}
|
24
|
+
mock.put "/people/sort.xml?by=name", {}, nil, 204
|
25
|
+
mock.delete "/people/deactivate.xml?name=Matz", {}, nil, 200
|
26
|
+
mock.delete "/people/1/deactivate.xml", {}, nil, 200
|
27
|
+
mock.post "/people/new/register.xml", {}, @ryan, 201, 'Location' => '/people/5.xml'
|
28
|
+
mock.post "/people/1/register.xml", {}, @matz, 201
|
29
|
+
mock.get "/people/1/addresses/1.xml", {}, @addy
|
30
|
+
mock.get "/people/1/addresses/1/deep.xml", {}, @addy_deep
|
31
|
+
mock.put "/people/1/addresses/1/normalize_phone.xml?locale=US", {}, nil, 204
|
32
|
+
mock.put "/people/1/addresses/sort.xml?by=name", {}, nil, 204
|
33
|
+
mock.post "/people/1/addresses/new/link.xml", {}, { :street => '12345 Street' }.to_xml(:root => 'address'), 201, 'Location' => '/people/1/addresses/2.xml'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def teardown
|
38
|
+
ActiveResource::HttpMock.reset!
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_custom_collection_method
|
42
|
+
# GET
|
43
|
+
assert_equal([{ "id" => 1, "name" => 'Matz' }], Person.get(:retrieve, :name => 'Matz'))
|
44
|
+
|
45
|
+
# POST
|
46
|
+
assert_equal(ActiveResource::Response.new("", 201, {}), Person.post(:hire, :name => 'Matz'))
|
47
|
+
|
48
|
+
# PUT
|
49
|
+
assert_equal ActiveResource::Response.new("", 204, {}),
|
50
|
+
Person.put(:promote, {:name => 'Matz'}, 'atestbody')
|
51
|
+
assert_equal ActiveResource::Response.new("", 204, {}), Person.put(:sort, :by => 'name')
|
52
|
+
|
53
|
+
# DELETE
|
54
|
+
Person.delete :deactivate, :name => 'Matz'
|
55
|
+
|
56
|
+
# Nested resource
|
57
|
+
assert_equal ActiveResource::Response.new("", 204, {}), StreetAddress.put(:sort, :person_id => 1, :by => 'name')
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_custom_element_method
|
61
|
+
# Test GET against an element URL
|
62
|
+
assert_equal Person.find(1).get(:shallow), {"id" => 1, "name" => 'Matz'}
|
63
|
+
assert_equal Person.find(1).get(:deep), {"id" => 1, "name" => 'Matz', "other" => 'other'}
|
64
|
+
|
65
|
+
# Test PUT against an element URL
|
66
|
+
assert_equal ActiveResource::Response.new("", 204, {}), Person.find(1).put(:promote, {:position => 'Manager'}, 'body')
|
67
|
+
|
68
|
+
# Test DELETE against an element URL
|
69
|
+
assert_equal ActiveResource::Response.new("", 200, {}), Person.find(1).delete(:deactivate)
|
70
|
+
|
71
|
+
# With nested resources
|
72
|
+
assert_equal StreetAddress.find(1, :params => { :person_id => 1 }).get(:deep),
|
73
|
+
{ "id" => 1, "street" => '12345 Street', "zip" => "27519" }
|
74
|
+
assert_equal ActiveResource::Response.new("", 204, {}),
|
75
|
+
StreetAddress.find(1, :params => { :person_id => 1 }).put(:normalize_phone, :locale => 'US')
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_custom_new_element_method
|
79
|
+
# Test POST against a new element URL
|
80
|
+
ryan = Person.new(:name => 'Ryan')
|
81
|
+
assert_equal ActiveResource::Response.new(@ryan, 201, {'Location' => '/people/5.xml'}), ryan.post(:register)
|
82
|
+
|
83
|
+
# Test POST against a nested collection URL
|
84
|
+
addy = StreetAddress.new(:street => '123 Test Dr.', :person_id => 1)
|
85
|
+
assert_equal ActiveResource::Response.new({ :street => '12345 Street' }.to_xml(:root => 'address'),
|
86
|
+
201, {'Location' => '/people/1/addresses/2.xml'}),
|
87
|
+
addy.post(:link)
|
88
|
+
|
89
|
+
matz = Person.new(:id => 1, :name => 'Matz')
|
90
|
+
assert_equal ActiveResource::Response.new(@matz, 201), matz.post(:register)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_find_custom_resources
|
94
|
+
assert_equal 'Matz', Person.find(:all, :from => :managers).first.name
|
95
|
+
end
|
96
|
+
end
|