提交 79ac05f5 编写于 作者: S Sean Griffin

Merge pull request #22506 from derekprior/dp-redirect_to_back_or_default

Add `redirect_to_back_or_default`
* Deprecate `redirect_to :back` in favor of `redirect_back`, which accepts a
required `fallback_location` argument, thus eliminating the possibility of a
`RedirectBackError`.
*Derek Prior*
* Add `redirect_back` method to `ActionController::Redirecting` to provide a
way to safely redirect to the `HTTP_REFERER` if it is present, falling back
to a provided redirect otherwise.
*Derek Prior*
* `ActionController::TestCase` will be moved to it's own gem in Rails 5.1
With the speed improvements made to `ActionDispatch::IntegrationTest` we no
......
......@@ -20,8 +20,6 @@ module Redirecting
# * <tt>String</tt> starting with <tt>protocol://</tt> (like <tt>http://</tt>) or a protocol relative reference (like <tt>//</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>Proc</tt> - A block that will be executed in the controller's context. Should return any option accepted by +redirect_to+.
# * <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:
#
......@@ -30,7 +28,6 @@ module Redirecting
# redirect_to "http://www.rubyonrails.org"
# redirect_to "/images/screenshot.jpg"
# redirect_to articles_url
# redirect_to :back
# redirect_to proc { edit_post_url(@post) }
#
# The redirection happens as a "302 Found" header unless otherwise specified using the <tt>:status</tt> option:
......@@ -61,10 +58,6 @@ module Redirecting
# 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,
# <tt>ActionController::RedirectBackError</tt> will be raised. You
# may specify some fallback behavior for this case by rescuing
# <tt>ActionController::RedirectBackError</tt>.
def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise ActionControllerError.new("Cannot redirect to a parameter hash!") if options.is_a?(ActionController::Parameters)
......@@ -75,6 +68,26 @@ def redirect_to(options = {}, response_status = {}) #:doc:
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
end
# Redirects the browser to the page that issued the request if possible,
# otherwise redirects to provided default fallback location.
#
# redirect_back fallback_location: { action: "show", id: 5 }
# redirect_back fallback_location: post
# redirect_back fallback_location: "http://www.rubyonrails.org"
# redirect_back fallback_location: "/images/screenshot.jpg"
# redirect_back fallback_location: articles_url
# redirect_back fallback_location: proc { edit_post_url(@post) }
#
# All options that can be passed to <tt>redirect_to</tt> are accepted as
# options and the behavior is indetical.
def redirect_back(fallback_location:, **args)
if referer = request.headers["Referer"]
redirect_to referer, **args
else
redirect_to fallback_location, **args
end
end
def _compute_redirect_to_location(request, options) #:nodoc:
case options
# The scheme name consist of a letter followed by any combination of
......@@ -87,6 +100,12 @@ def _compute_redirect_to_location(request, options) #:nodoc:
when String
request.protocol + request.host_with_port + options
when :back
ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
`redirect_to :back` is deprecated and will be removed from Rails 5.1.
Please use `redirect_back(fallback_location: fallback_location)` where
`fallback_location` represents the location to use if the request has
no HTTP referer information.
MESSAGE
request.headers["Referer"] or raise RedirectBackError
when Proc
_compute_redirect_to_location request, options.call
......
......@@ -42,6 +42,10 @@ def redirect_to_back_with_status
redirect_to :back, :status => 307
end
def redirect_back_with_status
redirect_back(fallback_location: "/things/stuff", status: 307)
end
def host_redirect
redirect_to :action => "other_host", :only_path => false, :host => 'other.test.host'
end
......@@ -187,7 +191,11 @@ def test_relative_url_redirect_with_status_hash
def test_redirect_to_back_with_status
@request.env["HTTP_REFERER"] = "http://www.example.com/coming/from"
get :redirect_to_back_with_status
assert_deprecated do
get :redirect_to_back_with_status
end
assert_response 307
assert_equal "http://www.example.com/coming/from", redirect_to_url
end
......@@ -236,7 +244,11 @@ def test_redirect_to_url_with_network_path_reference
def test_redirect_to_back
@request.env["HTTP_REFERER"] = "http://www.example.com/coming/from"
get :redirect_to_back
assert_deprecated do
get :redirect_to_back
end
assert_response :redirect
assert_equal "http://www.example.com/coming/from", redirect_to_url
end
......@@ -244,10 +256,32 @@ def test_redirect_to_back
def test_redirect_to_back_with_no_referer
assert_raise(ActionController::RedirectBackError) {
@request.env["HTTP_REFERER"] = nil
assert_deprecated do
get :redirect_to_back
end
get :redirect_to_back
}
end
def test_redirect_back
referer = "http://www.example.com/coming/from"
@request.env["HTTP_REFERER"] = referer
get :redirect_back_with_status
assert_response 307
assert_equal referer, redirect_to_url
end
def test_redirect_back_with_no_referer
get :redirect_back_with_status
assert_response 307
assert_equal "http://test.host/things/stuff", redirect_to_url
end
def test_redirect_to_record
with_routing do |set|
set.draw do
......
......@@ -1150,7 +1150,7 @@ class ApplicationController < ActionController::Base
def user_not_authorized
flash[:error] = "You don't have access to this section."
redirect_to :back
redirect_back(fallback_location: root_path)
end
end
......
......@@ -622,10 +622,13 @@ Another way to handle returning responses to an HTTP request is with `redirect_t
redirect_to photos_url
```
You can use `redirect_to` with any arguments that you could use with `link_to` or `url_for`. There's also a special redirect that sends the user back to the page they just came from:
You can use `redirect_back` to return the user to the page they just came from.
This location is pulled from the `HTTP_REFERER` header which is not guaranteed
to be set by the browser, so you must provide the `fallback_location`
to use in this case.
```ruby
redirect_to :back
redirect_back(fallback_location: root_path)
```
#### Getting a Different Redirect Status Code
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册