HTTP Redirect Response in Turbo

I’m working on updating an application from Turbolinks/UJS to Turbo and have a few questions regarding the changes related to HTTP redirect responses (questions bolded below).

The documentation says my redirects should now return a HTTP 303 See Other. From other research, I’ve come to understand that this is because when a HTTP 302 Found is returned, it is pointing to the new location of the resource but it might be assumed that we still want to carry out the original HTTP method at that new location. OTOH, a 303 is not saying this is the new location for that originally requested resource, but instead the location is a different resource related to the request. Since it’s a different resource we should not assume the same HTTP method. I’m guess the assumed HTTP method to this new resource is a GET request so the client can presumably learn about this related resource before then possibly carrying out further actions on that resource using other HTTP methods?

This is of course different from how browsers operate. A browser form, sending a POST request and receiving redirect response, issues a GET request at the indicated location regardless of the type of redirect.

I’ve also see some indication from other research that this maybe only needs to be done on the destroy action. The template in Rails seems to support this as it only has :see_other on destroy but not create and update. Is this because the destroy trigger is a Turbo-enabled link in the default templates while the create and update are Turbo-enabled forms? Does Turbo when submitting a form try to emulate the behavior of a browser submission by following the redirect with a GET regardless of redirect type? Where is the behavior for that defined in the Turbo?

Then I came across this PR that seems to try make the type of redirect not matter. It seems to change the method on the fetch call to always be a POST (if non-GET) and then encode the real HTTP method using the _method param hack. Since POST requests seem to emulate browser behavior in Turbo, does this mean that all Turbo requests (form or link regardless of method type) are good with any sort of redirect response? I’m assuming this part of turbo-rails and not Turbo proper since the _method param hack is a Rails thing? Does this mean it should be a 303 response generally for Turbo but in the special case of using Turbo with Rails any sort of redirect will work? Testing this out in my application shows this to be the case. My destroy operates correctly without the :see_other.

Finally, some semantic questions. Is the work on PR 370 just a crutch to help existing apps migrate to Turbo and greenfield development should be using :see_other to be semantically correct even if the 302 works because of the crutch? It seems if we are going for semantic correctness why wouldn’t we also want to use see_other on create and update actions? If :see_other really should be returned for most responses to be semantically correct then is there a way to make that the default in Rails and then only use :found if we really want to semantically indicate a resource is at a new location and the client should send their original HTTP method to that new location?

1 Like

Thanks e_a for posting these detailed questions! After searching for months for a reliable way to go with turbo, I wrote the render_turbo_stream gem, which includes a demo project.

I cannot answer your questions in detail and I cannot say if these details will change in the next versions of Turbo because Turbo is in an early state.

In general: Yes, a :post request triggers a turbo request, a :get usually does not. I found a way to restrict the response to turbo on the render method with the formats: [:turbo_stream] tag, and so I was able to decide on the controller how to handle the response.

Along the way, I bypassed these details and found a stable way to create CRUD controllers within a turbo frame.