Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added alert/notice from 2-3-stable and refactored redirect_to into ju…

…st living in Redirector [DHH]
  • Loading branch information...
commit fa575973b1ad5adb7115a18c4c1c7c31500e73b2 1 parent 2bfa477
David Heinemeier Hansson dhh authored
12 actionpack/CHANGELOG
View
@@ -1,5 +1,17 @@
*Edge*
+* Added :alert, :notice, and :flash as options to ActionController::Base#redirect_to that'll automatically set the proper flash before the redirection [DHH]. Examples:
+
+ flash[:notice] = 'Post was created'
+ redirect_to(@post)
+
+ ...becomes:
+
+ redirect_to(@post, :notice => 'Post was created')
+
+* Added ActionController::Base#notice/= and ActionController::Base#alert/= as a convenience accessors in both the controller and the view for flash[:notice]/= and flash[:alert]/= [DHH]
+
+
* Introduce grouped_collection_select helper. #1249 [Dan Codeape, Erik Ostrom]
* Make sure javascript_include_tag/stylesheet_link_tag does not append ".js" or ".css" onto external urls. #1664 [Matthew Rudy Jacobs]
66 actionpack/lib/action_controller/base.rb
View
@@ -106,71 +106,5 @@ def render_to_string(action = nil, options = {}, &blk)
options = _normalize_options(action, options, &blk)
super(options)
end
-
- # Redirects the browser to the target specified in +options+. This parameter can take one of three forms:
- #
- # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
- # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
- # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
- # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
- # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
- # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
- #
- # 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
- #
- # When using <tt>redirect_to :back</tt>, 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?
-
- 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
-
- url = 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
-
- super(url, status)
- end
-
- private
- 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
41 actionpack/lib/action_controller/metal/flash.rb
View
@@ -30,6 +30,10 @@ module Flash
include Session
+ included do
+ helper_method :alert, :notice
+ end
+
class FlashNow #:nodoc:
def initialize(flash)
@flash = flash
@@ -147,6 +151,27 @@ def flash #:doc:
@_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 @@ def reset_session
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
86 actionpack/lib/action_controller/metal/redirector.rb
View
@@ -11,12 +11,88 @@ module Redirector
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:
+ #
+ # * <tt>Hash</tt> - The URL will be generated by calling url_for with the +options+.
+ # * <tt>Record</tt> - The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record.
+ # * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) - Is passed straight through as the target for redirection.
+ # * <tt>String</tt> not containing a protocol - The current protocol and host is prepended to the string.
+ # * <tt>:back</tt> - Back to the page that issued the request. Useful for forms that are triggered from multiple places.
+ # Short-hand for <tt>redirect_to(request.env["HTTP_REFERER"])</tt>
+ #
+ # 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 <tt>redirect_to :back</tt>, 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 = "<html><body>You are being <a href=\"#{ERB::Util.h(url)}\">redirected</a>.</body></html>"
+
+ self.status = _extract_redirect_to_status(options, response_status)
+ self.location = _compute_redirect_to_location(options)
+ self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(location)}\">redirected</a>.</body></html>"
+
+ 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
29 actionpack/test/controller/flash_test.rb
View
@@ -72,6 +72,18 @@ def halt_and_redir
redirect_to :action => "std_action"
@flash_copy = {}.update(flash)
end
+
+ def redirect_with_alert
+ redirect_to '/nowhere', :alert => "Beware the nowheres!"
+ end
+
+ def redirect_with_notice
+ redirect_to '/somewhere', :notice => "Good luck in the somewheres!"
+ end
+
+ def redirect_with_other_flashes
+ redirect_to '/wonderland', :flash => { :joyride => "Horses!" }
+ end
end
tests TestController
@@ -160,4 +172,19 @@ def test_keep_and_discard_return_values
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep()) # nothing passed
assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep(nil)) # nothing passed
end
-end
+
+ def test_redirect_to_with_alert
+ get :redirect_with_alert
+ assert_equal "Beware the nowheres!", @controller.send(:flash)[:alert]
+ end
+
+ def test_redirect_to_with_notice
+ get :redirect_with_notice
+ assert_equal "Good luck in the somewheres!", @controller.send(:flash)[:notice]
+ end
+
+ def test_redirect_to_with_other_flashes
+ get :redirect_with_other_flashes
+ assert_equal "Horses!", @controller.send(:flash)[:joyride]
+ end
+end
2  railties/lib/rails/generators/erb/scaffold/templates/layout.html.erb
View
@@ -7,7 +7,7 @@
</head>
<body>
-<p class="notice"><%%= flash[:notice] %></p>
+<p class="notice"><%%= notice %></p>
<%%= yield %>
6 railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb
View
@@ -46,8 +46,7 @@ def create
respond_to do |format|
if @<%= orm_instance.save %>
- flash[:notice] = '<%= class_name %> was successfully created.'
- format.html { redirect_to(@<%= file_name %>) }
+ format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully created.') }
format.xml { render :xml => @<%= file_name %>, :status => :created, :location => @<%= file_name %> }
else
format.html { render :action => "new" }
@@ -63,8 +62,7 @@ def update
respond_to do |format|
if @<%= orm_instance.update_attributes("params[:#{file_name}]") %>
- flash[:notice] = '<%= class_name %> was successfully updated.'
- format.html { redirect_to(@<%= file_name %>) }
+ format.html { redirect_to(@<%= file_name %>, :notice => '<%= class_name %> was successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
Please sign in to comment.
Something went wrong with that request. Please try again.