mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Added respond_with.
Signed-off-by: Yehuda Katz <wycats@gmail.com>
This commit is contained in:
parent
bbe86077c2
commit
09de34ca56
3 changed files with 208 additions and 26 deletions
|
@ -145,8 +145,45 @@ module ActionController #:nodoc:
|
||||||
# environment.rb as follows.
|
# environment.rb as follows.
|
||||||
#
|
#
|
||||||
# Mime::Type.register "image/jpg", :jpg
|
# Mime::Type.register "image/jpg", :jpg
|
||||||
|
#
|
||||||
|
# Respond to also allows you to specify a common block for different formats by using any:
|
||||||
|
#
|
||||||
|
# def index
|
||||||
|
# @people = Person.find(:all)
|
||||||
|
#
|
||||||
|
# respond_to do |format|
|
||||||
|
# format.html
|
||||||
|
# format.any(:xml, :json) { render request.format.to_sym => @people }
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# In the example above, if the format is xml, it will render:
|
||||||
|
#
|
||||||
|
# render :xml => @people
|
||||||
|
#
|
||||||
|
# Or if the format is json:
|
||||||
|
#
|
||||||
|
# render :json => @people
|
||||||
|
#
|
||||||
|
# Since this is a common pattern, you can use the class method respond_to
|
||||||
|
# with the respond_with method to have the same results:
|
||||||
|
#
|
||||||
|
# class PeopleController < ApplicationController
|
||||||
|
# respond_to :html, :xml, :json
|
||||||
|
#
|
||||||
|
# def index
|
||||||
|
# @people = Person.find(:all)
|
||||||
|
# respond_with(@person)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Be sure to check respond_with and respond_to documentation for more examples.
|
||||||
|
#
|
||||||
def respond_to(*mimes, &block)
|
def respond_to(*mimes, &block)
|
||||||
|
options = mimes.extract_options!
|
||||||
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
|
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
|
||||||
|
|
||||||
|
resource = options.delete(:with)
|
||||||
responder = Responder.new
|
responder = Responder.new
|
||||||
block.call(responder) if block_given?
|
block.call(responder) if block_given?
|
||||||
|
|
||||||
|
@ -154,41 +191,117 @@ module ActionController #:nodoc:
|
||||||
mimes.each { |mime| responder.send(mime) }
|
mimes.each { |mime| responder.send(mime) }
|
||||||
|
|
||||||
if format = request.negotiate_mime(responder.order)
|
if format = request.negotiate_mime(responder.order)
|
||||||
# TODO It should be just: self.formats = [ :foo ]
|
respond_to_block_or_template_or_resource(format, resource,
|
||||||
self.formats = [format.to_sym]
|
options, &responder.response_for(format))
|
||||||
self.content_type = format
|
|
||||||
self.template.formats = [format.to_sym]
|
|
||||||
|
|
||||||
if response = responder.response_for(format)
|
|
||||||
response.call
|
|
||||||
else
|
|
||||||
default_render
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
head :not_acceptable
|
head :not_acceptable
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
# respond_with allows you to respond an action with a given resource. It
|
||||||
|
# requires that you set your class with a :respond_to method with the
|
||||||
|
# formats allowed:
|
||||||
|
#
|
||||||
|
# class PeopleController < ApplicationController
|
||||||
|
# respond_to :html, :xml, :json
|
||||||
|
#
|
||||||
|
# def index
|
||||||
|
# @people = Person.find(:all)
|
||||||
|
# respond_with(@person)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# When a request comes with format :xml, the respond_with will first search
|
||||||
|
# for a template as person/index.xml, if the template is not available, it
|
||||||
|
# will see if the given resource responds to :to_xml.
|
||||||
|
#
|
||||||
|
# If neither are available, it will raise an error.
|
||||||
|
#
|
||||||
|
# Extra parameters given to respond_with are used when :to_format is invoked.
|
||||||
|
# This allows you to set status and location for several formats at the same
|
||||||
|
# time. Consider this restful controller response on create for both xml
|
||||||
|
# and json formats:
|
||||||
|
#
|
||||||
|
# class PeopleController < ApplicationController
|
||||||
|
# respond_to :xml, :json
|
||||||
|
#
|
||||||
|
# def create
|
||||||
|
# @person = Person.new(params[:person])
|
||||||
|
#
|
||||||
|
# if @person.save
|
||||||
|
# respond_with(@person, :status => :ok, :location => person_url(@person))
|
||||||
|
# else
|
||||||
|
# respond_with(@person.errors, :status => :unprocessable_entity)
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Finally, respond_with also accepts blocks, as in respond_to. Let's take
|
||||||
|
# the same controller and create action above and add common html behavior:
|
||||||
|
#
|
||||||
|
# class PeopleController < ApplicationController
|
||||||
|
# respond_to :html, :xml, :json
|
||||||
|
#
|
||||||
|
# def create
|
||||||
|
# @person = Person.new(params[:person])
|
||||||
|
#
|
||||||
|
# if @person.save
|
||||||
|
# options = { :status => :ok, :location => person_url(@person) }
|
||||||
|
#
|
||||||
|
# respond_with(@person, options) do |format|
|
||||||
|
# format.html { redirect_to options[:location] }
|
||||||
|
# end
|
||||||
|
# else
|
||||||
|
# respond_with(@person.errors, :status => :unprocessable_entity) do
|
||||||
|
# format.html { render :action => :new }
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
def respond_with(resource, options={}, &block)
|
||||||
|
respond_to(options.merge!(:with => resource), &block)
|
||||||
|
end
|
||||||
|
|
||||||
# Collect mimes declared in the class method respond_to valid for the
|
protected
|
||||||
# current action.
|
|
||||||
#
|
|
||||||
def collect_mimes_from_class_level #:nodoc:
|
|
||||||
action = action_name.to_sym
|
|
||||||
|
|
||||||
mimes_for_respond_to.keys.select do |mime|
|
def respond_to_block_or_template_or_resource(format, resource, options)
|
||||||
config = mimes_for_respond_to[mime]
|
# TODO It should be just: self.formats = [ :foo ]
|
||||||
|
self.formats = [format.to_sym]
|
||||||
|
self.content_type = format
|
||||||
|
self.template.formats = [format.to_sym]
|
||||||
|
|
||||||
if config[:except]
|
return yield if block_given?
|
||||||
!config[:except].include?(action)
|
|
||||||
elsif config[:only]
|
begin
|
||||||
config[:only].include?(action)
|
default_render
|
||||||
else
|
rescue ActionView::MissingTemplate => e
|
||||||
true
|
if resource && resource.respond_to?("to_#{format.to_sym}")
|
||||||
end
|
render options.merge(format.to_sym => resource)
|
||||||
|
else
|
||||||
|
raise e
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Collect mimes declared in the class method respond_to valid for the
|
||||||
|
# current action.
|
||||||
|
#
|
||||||
|
def collect_mimes_from_class_level #:nodoc:
|
||||||
|
action = action_name.to_sym
|
||||||
|
|
||||||
|
mimes_for_respond_to.keys.select do |mime|
|
||||||
|
config = mimes_for_respond_to[mime]
|
||||||
|
|
||||||
|
if config[:except]
|
||||||
|
!config[:except].include?(action)
|
||||||
|
elsif config[:only]
|
||||||
|
config[:only].include?(action)
|
||||||
|
else
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class Responder #:nodoc:
|
class Responder #:nodoc:
|
||||||
attr_accessor :order
|
attr_accessor :order
|
||||||
|
|
|
@ -471,8 +471,20 @@ class RespondToControllerTest < ActionController::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class RespondResource
|
||||||
|
undef_method :to_json
|
||||||
|
|
||||||
|
def to_xml
|
||||||
|
"XML"
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_js
|
||||||
|
"JS"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class RespondWithController < ActionController::Base
|
class RespondWithController < ActionController::Base
|
||||||
respond_to :html
|
respond_to :html, :json
|
||||||
respond_to :xml, :except => :using_defaults
|
respond_to :xml, :except => :using_defaults
|
||||||
respond_to :js, :only => :using_defaults
|
respond_to :js, :only => :using_defaults
|
||||||
|
|
||||||
|
@ -485,6 +497,23 @@ class RespondWithController < ActionController::Base
|
||||||
def using_defaults_with_type_list
|
def using_defaults_with_type_list
|
||||||
respond_to(:js, :xml)
|
respond_to(:js, :xml)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def using_resource
|
||||||
|
respond_with(RespondResource.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
def using_resource_with_options
|
||||||
|
respond_with(RespondResource.new, :status => :unprocessable_entity) do |format|
|
||||||
|
format.js
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def _render_js(js, options)
|
||||||
|
self.content_type ||= Mime::JS
|
||||||
|
self.response_body = js.respond_to?(:to_js) ? js.to_js : js
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class RespondWithControllerTest < ActionController::TestCase
|
class RespondWithControllerTest < ActionController::TestCase
|
||||||
|
@ -530,6 +559,37 @@ class RespondWithControllerTest < ActionController::TestCase
|
||||||
assert_equal "<p>Hello world!</p>\n", @response.body
|
assert_equal "<p>Hello world!</p>\n", @response.body
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_using_resource
|
||||||
|
@request.accept = "text/html"
|
||||||
|
get :using_resource
|
||||||
|
assert_equal "text/html", @response.content_type
|
||||||
|
assert_equal "Hello world!", @response.body
|
||||||
|
|
||||||
|
@request.accept = "application/xml"
|
||||||
|
get :using_resource
|
||||||
|
assert_equal "application/xml", @response.content_type
|
||||||
|
assert_equal "XML", @response.body
|
||||||
|
|
||||||
|
@request.accept = "application/json"
|
||||||
|
assert_raise ActionView::MissingTemplate do
|
||||||
|
get :using_resource
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_using_resource_with_options
|
||||||
|
@request.accept = "application/xml"
|
||||||
|
get :using_resource_with_options
|
||||||
|
assert_equal "application/xml", @response.content_type
|
||||||
|
assert_equal 422, @response.status
|
||||||
|
assert_equal "XML", @response.body
|
||||||
|
|
||||||
|
@request.accept = "text/javascript"
|
||||||
|
get :using_resource_with_options
|
||||||
|
assert_equal "text/javascript", @response.content_type
|
||||||
|
assert_equal 422, @response.status
|
||||||
|
assert_equal "JS", @response.body
|
||||||
|
end
|
||||||
|
|
||||||
def test_not_acceptable
|
def test_not_acceptable
|
||||||
@request.accept = "application/xml"
|
@request.accept = "application/xml"
|
||||||
get :using_defaults
|
get :using_defaults
|
||||||
|
@ -538,6 +598,14 @@ class RespondWithControllerTest < ActionController::TestCase
|
||||||
@request.accept = "text/html"
|
@request.accept = "text/html"
|
||||||
get :using_defaults_with_type_list
|
get :using_defaults_with_type_list
|
||||||
assert_equal 406, @response.status
|
assert_equal 406, @response.status
|
||||||
|
|
||||||
|
@request.accept = "application/json"
|
||||||
|
get :using_defaults_with_type_list
|
||||||
|
assert_equal 406, @response.status
|
||||||
|
|
||||||
|
@request.accept = "text/javascript"
|
||||||
|
get :using_resource
|
||||||
|
assert_equal 406, @response.status
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
1
actionpack/test/fixtures/respond_with/using_resource.html.erb
vendored
Normal file
1
actionpack/test/fixtures/respond_with/using_resource.html.erb
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Hello world!
|
Loading…
Reference in a new issue