A HTTP 302 Found redirect to PATCH and DELETE requests will be followed with PATCH or DELETE. Redirect responses to GET and POST will be followed with a GET. The Rails form_for helper will use a workaround to send POST requests with a _method param to avoid this issue for PATCH/DELETE.
If you make requests yourself, watch out for the following behavior.
When you make an AJAX request PATCH /foo and the /foo action redirects to /bar, browsers will request PATCH /bar. You probably expected the second request to be GET /bar, since we're used to redirects always resulting in a GET request.
# Browser sends
PATCH /foo HTTP/1.1
# Server responds
HTTP/1.1 302 Found
Location: /bar
# Browser follows redirect
PATCH /bar
# Server responds
HTTP/1.1 404 Not Found
This is also true on some browsers for DELETE, or in general for any AJAX call that is neither GET or POST.
Some workarounds for this issue below.
Fix on the server: Redirect with a modern status code
If your redirecting action redirects with a HTTP status code of 303 See Other the browser will always follow up with a GET request, even if the requesting method is PATCH or DELETE:
def foo
redirect_to '/bar', status: :see_other
end
See Modern HTTP Status codes for redirecting for more background.
Fix on the client: Make a POST request with method override
The default configuration Rails and Sinatra includes a
Rack middleware
Show archive.org snapshot
that lets you control the HTTP method used for routing by POSTing with a _method param.
In JS this would be:
fetch('/foo', { method: 'POST', body: new URLSearchParams({ _method: 'PATCH' }) });
Since the request is now a POST for the browser, it will follow a redirect with GET as expected.
This is also what
Unpoly
Show archive.org snapshot
or the Rails unobtrusive Javascript adapter does when you annotate a link with data-method="PATCH".