Method: ActionController::Redirecting#redirect_to

Defined in:
lib/action_controller/metal/redirecting.rb

#redirect_to(options = {}, response_options = {}) ⇒ Object

Redirects the browser to the target specified in ‘options`. This parameter can be any one of:

  • ‘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://`) or a protocol relative reference (like `//`) - Is passed straight through as the target for redirection.

  • ‘String` not containing a protocol - The current protocol and host is prepended to the string.

  • ‘Proc` - A block that will be executed in the controller’s context. Should return any option accepted by ‘redirect_to`.

### Examples

redirect_to action: "show", id: 5
redirect_to @post
redirect_to "http://www.rubyonrails.org"
redirect_to "/images/screenshot.jpg"
redirect_to posts_url
redirect_to proc { edit_post_url(@post) }

The redirection happens as a ‘302 Found` header unless otherwise specified using the `:status` option:

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

The status code can either be a standard [HTTP Status code](www.iana.org/assignments/http-status-codes) as an integer, or a symbol representing the downcased, underscored and symbolized description. Note that the status code must be a 3xx HTTP code, or redirection will not occur.

If you are using XHR requests other than GET or POST and redirecting after the request then some browsers will follow the redirect using the original request method. This may lead to undesirable behavior such as a double DELETE. To work around this you can return a ‘303 See Other` status code which will be followed using a GET request.

redirect_to posts_url, status: :see_other
redirect_to action: 'index', status: 303

It is also possible to assign a flash message as part of the redirection. There are two special accessors for the commonly used flash names ‘alert` and `notice` as well as a general purpose `flash` bucket.

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")

Statements after ‘redirect_to` in our controller get executed, so `redirect_to` doesn’t stop the execution of the function. To terminate the execution of the function immediately after the ‘redirect_to`, use return.

redirect_to post_url(@post) and return

### Open Redirect protection

By default, Rails protects against redirecting to external hosts for your app’s safety, so called open redirects.

Here #redirect_to automatically validates the potentially-unsafe URL:

redirect_to params[:redirect_url]

The ‘action_on_open_redirect` configuration option controls the behavior when an unsafe redirect is detected:

  • ‘:log` - Logs a warning but allows the redirect

  • ‘:notify` - Sends an ActiveSupport notification for monitoring

  • ‘:raise` - Raises an UnsafeRedirectError

To allow any external redirects pass ‘allow_other_host: true`, though using a user-provided param in that case is unsafe.

redirect_to "https://rubyonrails.org", allow_other_host: true

See #url_from for more information on what an internal and safe URL is, or how to fall back to an alternate redirect URL in the unsafe case.

### Path Relative URL Redirect Protection

Rails also protects against potentially unsafe path relative URL redirects that don’t start with a leading slash. These can create security vulnerabilities:

redirect_to "example.com"     # Creates http://yourdomain.comexample.com
redirect_to "@attacker.com"   # Creates http://[email protected]
                              # which browsers interpret as user@host

You can configure how Rails handles these cases using:

config.action_controller.action_on_path_relative_redirect = :log    # default
config.action_controller.action_on_path_relative_redirect = :notify
config.action_controller.action_on_path_relative_redirect = :raise
  • ‘:log` - Logs a warning but allows the redirect

  • ‘:notify` - Sends an ActiveSupport notification but allows the redirect (includes stack trace to help identify the source)

  • ‘:raise` - Raises an UnsafeRedirectError



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/action_controller/metal/redirecting.rb', line 150

def redirect_to(options = {}, response_options = {})
  raise ActionControllerError.new("Cannot redirect to nil!") unless options
  raise AbstractController::DoubleRenderError if response_body

  allow_other_host = response_options.delete(:allow_other_host)

  proposed_status = _extract_redirect_to_status(options, response_options)

  redirect_to_location = _compute_redirect_to_location(request, options)
  _ensure_url_is_http_header_safe(redirect_to_location)

  self.location      = _enforce_open_redirect_protection(redirect_to_location, allow_other_host: allow_other_host)
  self.response_body = ""
  self.status        = proposed_status
end