From fa575973b1ad5adb7115a18c4c1c7c31500e73b2 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 17 Dec 2009 16:37:11 -0800 Subject: Added alert/notice from 2-3-stable and refactored redirect_to into just living in Redirector [DHH] --- actionpack/lib/action_controller/metal/flash.rb | 41 +++++++++++ .../lib/action_controller/metal/redirector.rb | 86 ++++++++++++++++++++-- 2 files changed, 122 insertions(+), 5 deletions(-) (limited to 'actionpack/lib/action_controller/metal') diff --git a/actionpack/lib/action_controller/metal/flash.rb b/actionpack/lib/action_controller/metal/flash.rb index 9d08ed6081..ae343444e2 100644 --- a/actionpack/lib/action_controller/metal/flash.rb +++ b/actionpack/lib/action_controller/metal/flash.rb @@ -30,6 +30,10 @@ module ActionController #:nodoc: include Session + included do + helper_method :alert, :notice + end + class FlashNow #:nodoc: def initialize(flash) @flash = flash @@ -147,6 +151,27 @@ module ActionController #:nodoc: @_flash end + # Convenience accessor for flash[:alert] + def alert + flash[:alert] + end + + # Convenience accessor for flash[:alert]= + def alert=(message) + flash[:alert] = message + end + + # Convenience accessor for flash[:notice] + def notice + flash[:notice] + end + + # Convenience accessor for flash[:notice]= + def notice=(message) + flash[:notice] = message + end + + protected def process_action(method_name) @_flash = nil @@ -159,5 +184,21 @@ module ActionController #:nodoc: super @_flash = nil end + + def redirect_to(options = {}, response_status_and_flash = {}) #:doc: + if alert = response_status_and_flash.delete(:alert) + flash[:alert] = alert + end + + if notice = response_status_and_flash.delete(:notice) + flash[:notice] = notice + end + + if other_flashes = response_status_and_flash.delete(:flash) + flash.update(other_flashes) + end + + super(options, response_status_and_flash) + end end end diff --git a/actionpack/lib/action_controller/metal/redirector.rb b/actionpack/lib/action_controller/metal/redirector.rb index b55f5e7bfc..a7bd5ee981 100644 --- a/actionpack/lib/action_controller/metal/redirector.rb +++ b/actionpack/lib/action_controller/metal/redirector.rb @@ -11,12 +11,88 @@ module ActionController extend ActiveSupport::Concern include AbstractController::Logger - def redirect_to(url, status) #:doc: + # Redirects the browser to the target specified in +options+. This parameter can take one of three forms: + # + # * Hash - The URL will be generated by calling url_for with the +options+. + # * Record - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record. + # * String starting with protocol:// (like http://) - Is passed straight through as the target for redirection. + # * String not containing a protocol - The current protocol and host is prepended to the string. + # * :back - Back to the page that issued the request. Useful for forms that are triggered from multiple places. + # Short-hand for redirect_to(request.env["HTTP_REFERER"]) + # + # Examples: + # redirect_to :action => "show", :id => 5 + # redirect_to post + # redirect_to "http://www.rubyonrails.org" + # redirect_to "/images/screenshot.jpg" + # redirect_to articles_url + # redirect_to :back + # + # The redirection happens as a "302 Moved" header unless otherwise specified. + # + # Examples: + # redirect_to post_url(@post), :status => :found + # redirect_to :action=>'atom', :status => :moved_permanently + # redirect_to post_url(@post), :status => 301 + # redirect_to :action=>'atom', :status => 302 + # + # It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names + # +alert+ and +notice+ as well as a general purpose +flash+ bucket. + # + # Examples: + # redirect_to post_url(@post), :alert => "Watch it, mister!" + # redirect_to post_url(@post), :status=> :found, :notice => "Pay attention to the road" + # redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id } + # redirect_to { :action=>'atom' }, :alert => "Something serious happened" + # + # When using redirect_to :back, if there is no referrer, + # RedirectBackError will be raised. You may specify some fallback + # behavior for this case by rescuing RedirectBackError. + def redirect_to(options = {}, response_status = {}) #:doc: + raise ActionControllerError.new("Cannot redirect to nil!") if options.nil? raise AbstractController::DoubleRenderError if response_body - logger.info("Redirected to #{url}") if logger && logger.info? - self.status = status - self.location = url.gsub(/[\r\n]/, '') - self.response_body = "You are being redirected." + + self.status = _extract_redirect_to_status(options, response_status) + self.location = _compute_redirect_to_location(options) + self.response_body = "You are being redirected." + + logger.info("Redirected to #{location}") if logger && logger.info? end + + private + def _extract_redirect_to_status(options, response_status) + status = if options.is_a?(Hash) && options.key?(:status) + _interpret_status(options.delete(:status)) + elsif response_status.key?(:status) + _interpret_status(response_status[:status]) + else + 302 + end + end + + def _compute_redirect_to_location(options) + case options + # The scheme name consist of a letter followed by any combination of + # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") + # characters; and is terminated by a colon (":"). + when %r{^\w[\w\d+.-]*:.*} + options + when String + request.protocol + request.host_with_port + options + when :back + raise RedirectBackError unless refer = request.headers["Referer"] + refer + else + url_for(options) + end.gsub(/[\r\n]/, '') + end + + def _interpret_status(status) + if status.is_a?(Symbol) + (ActionDispatch::StatusCodes::SYMBOL_TO_STATUS_CODE[status] || 500) + else + status.to_i + end + end end end -- cgit v1.2.3