If you are a Rails developer, chances are you have already used redirect_to
bunch of times. But have you ever wondered, how it works?
Suppose if you put this in your controller code and set the appropriate routing
def index
redirect_to "https://www.google.com"
end
Your browser will redirect you to google.com, which is fine. But how does your browser know to redirect to google.com?
The magic lies here https://github.com/rails/rails/blob/b738f1930f3c82f51741ef7241c1fee691d7deb2/actionpack/lib/action_controller/metal/redirecting.rb#L58
The code is this
def redirect_to(options = {}, response_options = {})
raise ActionControllerError.new("Cannot redirect to nil!") unless options
raise AbstractController::DoubleRenderError if response_body
self.status = _extract_redirect_to_status(options, response_options)
self.location = _compute_redirect_to_location(request, options)
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
end
Basically, the above code is setting the status as 302 by default. And location header to https://www.google.com
. And the response body to
You are being <a href="https://www.google.com">redirected</a>.
So when the browser receives a status of 3xx with a location header, it redirects!
In the browser, if you see the network, it looks like this
As you can see it's setting the status to 302
and Location to https://www.google.com
I was unsuccessful in seeing the response body in the browser, maybe that's just the browser's behavior. Someone can confirm this?
But I could see response body in curl
request
It looks like this
curl http://localhost:3000 -v
* Rebuilt URL to: http://localhost:3000/
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> GET / HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 302 Found
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Download-Options: noopen
< X-Permitted-Cross-Domain-Policies: none
< Referrer-Policy: strict-origin-when-cross-origin
< Location: https://www.google.com
< Content-Type: text/html; charset=utf-8
< Cache-Control: no-cache
< X-Request-Id: 660668ae-1176-4770-8e82-a6bb303efbbc
< X-Runtime: 0.029982
< Transfer-Encoding: chunked
<
* Connection #0 to host localhost left intact
<html><body>You are being <a href="https://www.google.com">redirected</a>.</body></html>%
So with our new-found knowledge, how about making our own redirect_to
behaviour in Rails? All we need to do is set a status
and Location header
def index
render plain: "You are being redirected to google.com", status: 302
response.headers['Location'] = 'https://www.google.com'
end
The above method also works like redirect_to
but looks a little ugly. But who cares :p
You can read more about how redirect works here https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
Top comments (4)
Great post. Really liked it.
Great! I love this kind of post where people dissect Rails methods. Thanks for sharing!
Glad you liked it, after getting comfortable with Rails, one has to look at what the magic is getting translated to!
Saw this gem of an article. I know this is and old post but still helps. Thanks for this!