mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
51f1f550da
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>
119 lines
5 KiB
Ruby
119 lines
5 KiB
Ruby
require 'active_support/core_ext/object/blank'
|
|
|
|
module ActiveResource
|
|
# A module to support custom REST methods and sub-resources, allowing you to break out
|
|
# of the "default" REST methods with your own custom resource requests. For example,
|
|
# say you use Rails to expose a REST service and configure your routes with:
|
|
#
|
|
# map.resources :people, :new => { :register => :post },
|
|
# :member => { :promote => :put, :deactivate => :delete }
|
|
# :collection => { :active => :get }
|
|
#
|
|
# This route set creates routes for the following HTTP requests:
|
|
#
|
|
# POST /people/new/register.xml # PeopleController.register
|
|
# PUT /people/1/promote.xml # PeopleController.promote with :id => 1
|
|
# DELETE /people/1/deactivate.xml # PeopleController.deactivate with :id => 1
|
|
# GET /people/active.xml # PeopleController.active
|
|
#
|
|
# Using this module, Active Resource can use these custom REST methods just like the
|
|
# standard methods.
|
|
#
|
|
# class Person < ActiveResource::Base
|
|
# self.site = "http://37s.sunrise.i:3000"
|
|
# end
|
|
#
|
|
# Person.new(:name => 'Ryan).post(:register) # POST /people/new/register.xml
|
|
# # => { :id => 1, :name => 'Ryan' }
|
|
#
|
|
# Person.find(1).put(:promote, :position => 'Manager') # PUT /people/1/promote.xml
|
|
# Person.find(1).delete(:deactivate) # DELETE /people/1/deactivate.xml
|
|
#
|
|
# Person.get(:active) # GET /people/active.xml
|
|
# # => [{:id => 1, :name => 'Ryan'}, {:id => 2, :name => 'Joe'}]
|
|
#
|
|
module CustomMethods
|
|
extend ActiveSupport::Concern
|
|
|
|
included do
|
|
class << self
|
|
alias :orig_delete :delete
|
|
|
|
# Invokes a GET to a given custom REST method. For example:
|
|
#
|
|
# Person.get(:active) # GET /people/active.xml
|
|
# # => [{:id => 1, :name => 'Ryan'}, {:id => 2, :name => 'Joe'}]
|
|
#
|
|
# Person.get(:active, :awesome => true) # GET /people/active.xml?awesome=true
|
|
# # => [{:id => 1, :name => 'Ryan'}]
|
|
#
|
|
# Note: the objects returned from this method are not automatically converted
|
|
# into ActiveResource::Base instances - they are ordinary Hashes. If you are expecting
|
|
# ActiveResource::Base instances, use the <tt>find</tt> class method with the
|
|
# <tt>:from</tt> option. For example:
|
|
#
|
|
# Person.find(:all, :from => :active)
|
|
def get(custom_method_name, options = {})
|
|
format.decode(connection.get(custom_method_collection_url(custom_method_name, options), headers).body)
|
|
end
|
|
|
|
def post(custom_method_name, options = {}, body = '')
|
|
connection.post(custom_method_collection_url(custom_method_name, options), body, headers)
|
|
end
|
|
|
|
def put(custom_method_name, options = {}, body = '')
|
|
connection.put(custom_method_collection_url(custom_method_name, options), body, headers)
|
|
end
|
|
|
|
def delete(custom_method_name, options = {})
|
|
# Need to jump through some hoops to retain the original class 'delete' method
|
|
if custom_method_name.is_a?(Symbol)
|
|
connection.delete(custom_method_collection_url(custom_method_name, options), headers)
|
|
else
|
|
orig_delete(custom_method_name, options)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
module ClassMethods
|
|
def custom_method_collection_url(method_name, options = {})
|
|
prefix_options, query_options = split_options(options)
|
|
"#{prefix(prefix_options)}#{collection_name}/#{method_name}.#{format.extension}#{query_string(query_options)}"
|
|
end
|
|
end
|
|
|
|
module InstanceMethods
|
|
def get(method_name, options = {})
|
|
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)
|
|
request_body = body.blank? ? encode : body
|
|
if new?
|
|
connection.post(custom_method_new_element_url(method_name, options), request_body, self.class.headers)
|
|
else
|
|
connection.post(custom_method_element_url(method_name, options), request_body, self.class.headers)
|
|
end
|
|
end
|
|
|
|
def put(method_name, options = {}, body = '')
|
|
connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
|
|
end
|
|
|
|
def delete(method_name, options = {})
|
|
connection.delete(custom_method_element_url(method_name, options), self.class.headers)
|
|
end
|
|
|
|
|
|
private
|
|
def custom_method_element_url(method_name, options = {})
|
|
"#{self.class.prefix(prefix_options)}#{self.class.collection_name}/#{id}/#{method_name}.#{self.class.format.extension}#{self.class.__send__(:query_string, options)}"
|
|
end
|
|
|
|
def custom_method_new_element_url(method_name, options = {})
|
|
"#{self.class.prefix(prefix_options)}#{self.class.collection_name}/new/#{method_name}.#{self.class.format.extension}#{self.class.__send__(:query_string, options)}"
|
|
end
|
|
end
|
|
end
|
|
end
|