Allow per Resource format settings

Previously, ActiveResource was using the connection level formatter for get requests. This made it impossible to use custom formatters per resource.

Additionally this commit makes the Connection request methods more consistent. It always returns a Response. The base will then decode it each the response using its format setting.

Merging this commit will allow users to add custom formatters on a per Resource basis. This enables handling pagination responses from the server side, a very common use case that was previously impossible without monkeypatching XmlFormat.

Signed-off-by: José Valim <jose.valim@gmail.com>
This commit is contained in:
Jacques Crocker 2010-09-18 03:09:37 -07:00 committed by José Valim
parent ee5ef67c44
commit 51f1f550da
5 changed files with 25 additions and 17 deletions

@ -678,7 +678,7 @@ def collection_path(prefix_options = {}, query_options = nil)
# Returns the new resource instance.
#
def build(attributes = {})
attrs = connection.get("#{new_element_path}").merge(attributes)
attrs = self.format.decode(connection.get("#{new_element_path}").body).merge(attributes)
self.new(attrs)
end
@ -850,11 +850,11 @@ def find_every(options)
instantiate_collection(get(from, options[:params]))
when String
path = "#{from}#{query_string(options[:params])}"
instantiate_collection(connection.get(path, headers) || [])
instantiate_collection(format.decode(connection.get(path, headers).body) || [])
else
prefix_options, query_options = split_options(options[:params])
path = collection_path(prefix_options, query_options)
instantiate_collection( (connection.get(path, headers) || []), prefix_options )
instantiate_collection( (format.decode(connection.get(path, headers).body) || []), prefix_options )
end
rescue ActiveResource::ResourceNotFound
# Swallowing ResourceNotFound exceptions and return nil - as per
@ -870,7 +870,7 @@ def find_one(options)
instantiate_record(get(from, options[:params]))
when String
path = "#{from}#{query_string(options[:params])}"
instantiate_record(connection.get(path, headers))
instantiate_record(format.decode(connection.get(path, headers).body))
end
end
@ -878,7 +878,7 @@ def find_one(options)
def find_single(scope, options)
prefix_options, query_options = split_options(options[:params])
path = element_path(scope, prefix_options, query_options)
instantiate_record(connection.get(path, headers), prefix_options)
instantiate_record(format.decode(connection.get(path, headers).body), prefix_options)
end
def instantiate_collection(collection, prefix_options = {})

@ -76,7 +76,7 @@ def ssl_options=(opts={})
# Executes a GET request.
# Used to get (find) resources.
def get(path, headers = {})
with_auth { format.decode(request(:get, path, build_request_headers(headers, :get, self.site.merge(path))).body) }
with_auth { request(:get, path, build_request_headers(headers, :get, self.site.merge(path))) }
end
# Executes a DELETE request (see HTTP protocol documentation if unfamiliar).

@ -54,7 +54,7 @@ class << self
#
# Person.find(:all, :from => :active)
def get(custom_method_name, options = {})
connection.get(custom_method_collection_url(custom_method_name, options), headers)
format.decode(connection.get(custom_method_collection_url(custom_method_name, options), headers).body)
end
def post(custom_method_name, options = {}, body = '')
@ -85,7 +85,7 @@ def custom_method_collection_url(method_name, options = {})
module InstanceMethods
def get(method_name, options = {})
connection.get(custom_method_element_url(method_name, options), self.class.headers)
self.class.format.decode(connection.get(custom_method_element_url(method_name, options), self.class.headers).body)
end
def post(method_name, options = {}, body = nil)

@ -132,7 +132,7 @@ def test_authorization_header_if_credentials_supplied_and_auth_type_is_digest
end
def test_get
david = @authenticated_conn.get("/people/2.xml")
david = decode(@authenticated_conn.get("/people/2.xml"))
assert_equal "David", david["name"]
end
@ -159,7 +159,7 @@ def test_head
def test_get_with_digest_auth_handles_initial_401_response_and_retries
@authenticated_conn.auth_type = :digest
response = @authenticated_conn.get("/people/2.xml")
assert_equal "David", response["name"]
assert_equal "David", decode(response)["name"]
end
def test_post_with_digest_auth_handles_initial_401_response_and_retries
@ -190,11 +190,11 @@ def test_head_with_digest_auth_handles_initial_401_response_and_retries
def test_get_with_digest_auth_caches_nonce
@authenticated_conn.auth_type = :digest
response = @authenticated_conn.get("/people/2.xml")
assert_equal "David", response["name"]
assert_equal "David", decode(response)["name"]
# There is no mock for this request with a non-cached nonce.
response = @authenticated_conn.get("/people/1.xml")
assert_equal "Matz", response["name"]
assert_equal "Matz", decode(response)["name"]
end
def test_retry_on_401_only_happens_with_digest_auth
@ -241,4 +241,8 @@ def request_digest_auth_header(uri, response)
def response_digest_auth_header
%Q(Digest realm="RailsTestApp", qop="auth", algorithm=MD5, nonce="#{@nonce}", opaque="ef6dfb078ba22298d366f99567814ffb")
end
def decode(response)
@authenticated_conn.format.decode(response.body)
end
end

@ -120,7 +120,7 @@ def test_timeout_accessor
end
def test_get
matz = @conn.get("/people/1.xml")
matz = decode(@conn.get("/people/1.xml"))
assert_equal "Matz", matz["name"]
end
@ -131,23 +131,23 @@ def test_head
end
def test_get_with_header
david = @conn.get("/people/2.xml", @header)
david = decode(@conn.get("/people/2.xml", @header))
assert_equal "David", david["name"]
end
def test_get_collection
people = @conn.get("/people.xml")
people = decode(@conn.get("/people.xml"))
assert_equal "Matz", people[0]["name"]
assert_equal "David", people[1]["name"]
end
def test_get_collection_single
people = @conn.get("/people_single_elements.xml")
people = decode(@conn.get("/people_single_elements.xml"))
assert_equal "Matz", people[0]["name"]
end
def test_get_collection_empty
people = @conn.get("/people_empty_elements.xml")
people = decode(@conn.get("/people_empty_elements.xml"))
assert_equal [], people
end
@ -250,4 +250,8 @@ def assert_response_raises(klass, code)
def handle_response(response)
@conn.__send__(:handle_response, response)
end
def decode(response)
@conn.format.decode(response.body)
end
end