This post was extracted and adapted from The Rails and Hotwire Codex.
In Rails, a conventional redirect in a controller action looks like:
def create # ... redirect_to root_path end
This sends a response with an HTTP status code of
The reason behind this is the spec for
302 Found states that the redirected request should use the same HTTP method as the original request. Due to legacy reasons, the
fetch (used by Turbo under the hood) implementation in most browsers will respond to a
302 Found response from a
POST request by issuing a
GET request to the redirected path. For all other HTTP methods, it will use the same method as the original request when redirecting.
Responding with a
303 See Other status ensures that the method used for the redirect is always
def create # ... redirect_to root_path, status: :see_other end
This anomaly with redirect codes isn't a massive problem in Rails because Rails forms use the only two browser native methods:
POST. Forms with different methods are rendered to use
POST with the method inserted as a hidden field which is then parsed by Rails before the request hits a controller.
<%= form_with(url: posts_path, method: :put) do |form| %> <%= form.text_field :name %> <%= form.submit %> <% end %>
<form action="/posts" accept-charset="UTF-8" method="post"> <input type="hidden" name="_method" value="put"> <input type="hidden" name="authenticity_token" value="..."> <input type="text" name="name" id="name"> <input type="submit" name="commit" value="Save"> </form>
However, this could potentially change as Rails integrates more tightly with Turbo. There are already a couple of use cases where
302 redirects can be problematic.
Turbo submits the form using the method specified in the
formmethod attribute when it's defined. The below form would submit using a
<%= form_with(url: posts_path) do |form| %> <%= form.text_field :name %> <%= form.submit formmethod: :put %> <% end %>
If your controller redirected using a
302 Found, that would result in another
PUT request to the redirected path.
Since Turbo intercepts form submissions, you can use any HTTP method in a
method attribute, not just
POST. This form will also submit with a
<form action="/posts" accept-charset="UTF-8" method="put"> <input type="text" name="name" id="name"> <input type="submit" value="Save"> </form>
Rails form helpers won't render this, but it's good to know what's possible!
As such, I believe it's good practice to ALWAYS redirect with a
303 See Other status code when using Turbo in a Rails app.
If you liked this post, check out my book, The Rails and Hotwire Codex, to level-up your Rails and Hotwire skills!