diff options
Diffstat (limited to 'actionpack/lib/action_controller/base')
-rw-r--r-- | actionpack/lib/action_controller/base/mime_responds.rb | 128 |
1 files changed, 81 insertions, 47 deletions
diff --git a/actionpack/lib/action_controller/base/mime_responds.rb b/actionpack/lib/action_controller/base/mime_responds.rb index f4a4007a43..9a6c8aa58b 100644 --- a/actionpack/lib/action_controller/base/mime_responds.rb +++ b/actionpack/lib/action_controller/base/mime_responds.rb @@ -177,19 +177,21 @@ module ActionController #:nodoc: # Be sure to check respond_with and respond_to documentation for more examples. # 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? - resource = options.delete(:with) responder = Responder.new - mimes = collect_mimes_from_class_level if mimes.empty? mimes.each { |mime| responder.send(mime) } block.call(responder) if block_given? if format = request.negotiate_mime(responder.order) - respond_to_block_or_template_or_resource(format, resource, - options, &responder.response_for(format)) + self.formats = [format.to_sym] + + if response = responder.response_for(format) + response.call + else + default_render + end else head :not_acceptable end @@ -200,11 +202,11 @@ module ActionController #:nodoc: # formats allowed: # # class PeopleController < ApplicationController - # respond_to :html, :xml, :json + # respond_to :xml, :json # # def index # @people = Person.find(:all) - # respond_with(@person) + # respond_with(@people) # end # end # @@ -214,67 +216,99 @@ module ActionController #:nodoc: # # 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: + # respond_with holds semantics for each HTTP verb. The example above cover + # GET requests. Let's check a POST request example: + # + # def create + # @person = Person.new(params[:person]) + # @person.save + # respond_with(@person) + # end + # + # Since the request is a POST, respond_with will check wether @people + # resource have errors or not. If it has errors, it will render the error + # object with unprocessable entity status (422). + # + # If no error was found, it will render the @people resource, with status + # created (201) and location header set to person_url(@people). + # + # If you also want to provide html behavior in the method above, you can + # supply a block to customize it: # # class PeopleController < ApplicationController - # respond_to :xml, :json + # respond_to :html, :xml, :json # Add :html to respond_to definition # # 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) + # @person = Person.new(params[:pe]) + # + # respond_with(@person) do |format| + # if @person.save + # flash[:notice] = 'Person was successfully created.' + # format.html { redirect_to @person } + # else + # format.html { render :action => "new" } + # end # 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: + # It works similarly for PUT requests: # - # class PeopleController < ApplicationController - # respond_to :html, :xml, :json + # def update + # @person = Person.find(params[:id]) + # @person.update_attributes(params[:person]) + # respond_with(@person) + # end # - # def create - # @person = Person.new(params[:person]) + # In case of failures, it works as POST requests, but in success failures + # it just reply status ok (200) to the client. # - # if @person.save - # options = { :status => :ok, :location => person_url(@person) } + # A DELETE request also works in the same way: # - # 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 + # def destroy + # @person = Person.find(params[:id]) + # @person.destroy + # respond_with(@person) # end # + # It just replies with status ok, indicating the record was successfuly + # destroyed. + # def respond_with(resource, options={}, &block) - respond_to(options.merge!(:with => resource), &block) + respond_to(&block) + rescue ActionView::MissingTemplate => e + format = self.formats.first + resource = normalize_resource_options_by_verb(resource, options) + + if resource.respond_to?(:"to_#{format}") + if options.delete(:no_content) + head options + else + render options.merge(format => resource) + end + else + raise e + end end protected - def respond_to_block_or_template_or_resource(format, resource, options) - self.formats = [format.to_sym] - return yield if block_given? + # Change respond with behavior based on the HTTP verb. + # + def normalize_resource_options_by_verb(resource_or_array, options) + resource = resource_or_array.is_a?(Array) ? resource_or_array.last : resource_or_array + has_errors = resource.respond_to?(:errors) && !resource.errors.empty? - begin - default_render - rescue ActionView::MissingTemplate => e - if resource && resource.respond_to?(:"to_#{format.to_sym}") - render options.merge(format.to_sym => resource) - else - raise e - end + if has_errors && (request.post? || request.put?) + options.reverse_merge!(:status => :unprocessable_entity) + return resource.errors + elsif request.post? + options.reverse_merge!(:status => :created, :location => resource_or_array) + elsif !request.get? + options.reverse_merge!(:status => :ok, :no_content => true) end + + return resource end # Collect mimes declared in the class method respond_to valid for the |