29294476f7241b4f50f872c50d89c009b51215a2
1 module ActionController
#:nodoc:
2 module MimeResponds
#:nodoc:
3 def self.included(base
)
5 include ActionController
::MimeResponds::InstanceMethods
10 # Without web-service support, an action which collects the data for displaying a list of people
11 # might look something like this:
14 # @people = Person.find(:all)
17 # Here's the same action, with web-service support baked in:
20 # @people = Person.find(:all)
22 # respond_to do |format|
24 # format.xml { render :xml => @people.to_xml }
28 # What that says is, "if the client wants HTML in response to this action, just respond as we
29 # would have before, but if the client wants XML, return them the list of people in XML format."
30 # (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
32 # Supposing you have an action that adds a new person, optionally creating their company
33 # (by name) if it does not already exist, without web-services, it might look like this:
36 # @company = Company.find_or_create_by_name(params[:company][:name])
37 # @person = @company.people.create(params[:person])
39 # redirect_to(person_list_url)
42 # Here's the same action, with web-service support baked in:
45 # company = params[:person].delete(:company)
46 # @company = Company.find_or_create_by_name(company[:name])
47 # @person = @company.people.create(params[:person])
49 # respond_to do |format|
50 # format.html { redirect_to(person_list_url) }
52 # format.xml { render :xml => @person.to_xml(:include => @company) }
56 # If the client wants HTML, we just redirect them back to the person list. If they want Javascript
57 # (format.js), then it is an RJS request and we render the RJS template associated with this action.
58 # Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also
59 # include the person's company in the rendered XML, so you get something like this:
71 # Note, however, the extra bit at the top of that action:
73 # company = params[:person].delete(:company)
74 # @company = Company.find_or_create_by_name(company[:name])
76 # This is because the incoming XML document (if a web-service request is in process) can only contain a
77 # single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):
79 # person[name]=...&person[company][name]=...&...
81 # And, like this (xml-encoded):
90 # In other words, we make the request so that it operates on a single entity's person. Then, in the action,
91 # we extract the company data from the request, find or create the company, and then create the new person
92 # with the remaining data.
94 # Note that you can define your own XML parameter parser which would allow you to describe multiple entities
95 # in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow
96 # and accept Rails' defaults, life will be much easier.
98 # If you need to use a MIME type which isn't supported by default, you can register your own handlers in
99 # environment.rb as follows.
101 # Mime::Type.register "image/jpg", :jpg
102 def respond_to(*types
, &block
)
103 raise ArgumentError
, "respond_to takes either types or a block, never both" unless types
.any
? ^ block
104 block
||= lambda
{ |responder
| types
.each
{ |type
| responder
.send(type
) } }
105 responder
= Responder
.new(self)
106 block
.call(responder
)
111 class Responder
#:nodoc:
112 def initialize(controller
)
113 @controller = controller
114 @request = controller
.request
115 @response = controller
.response
117 if ActionController
::Base.use_accept_header
118 @mime_type_priority = Array(Mime
::Type.lookup_by_extension(@request.parameters
[:format]) || @request.accepts
)
120 @mime_type_priority = [@request.format
]
127 def custom(mime_type
, &block
)
128 mime_type
= mime_type
.is_a
?(Mime
::Type) ? mime_type
: Mime
::Type.lookup(mime_type
.to_s
)
132 @responses[mime_type
] ||= Proc
.new
do
133 @response.template
.template_format
= mime_type
.to_sym
134 @response.content_type
= mime_type
.to_s
135 block_given
? ? block
.call
: @controller.send(:render, :action => @controller.action_name
)
139 def any(*args
, &block
)
141 args
.each
{ |type
| send(type
, &block
) }
143 custom(@mime_type_priority.first
, &block
)
147 def method_missing(symbol
, &block
)
148 mime_constant
= symbol
.to_s
.upcase
150 if Mime
::SET.include?(Mime
.const_get(mime_constant
))
151 custom(Mime
.const_get(mime_constant
), &block
)
158 for priority
in @mime_type_priority
159 if priority
== Mime
::ALL
160 @responses[@order.first
].call
163 if @responses[priority
]
164 @responses[priority
].call
165 return # mime type match found, be happy and return
170 if @order.include?(Mime
::ALL)
171 @responses[Mime
::ALL].call
173 @controller.send
:head, :not_acceptable