56

I am trying to get this link to work, performing a DELETE request:

<%= link_to "Sign Out", destroy_user_session_path, method: :delete %>

However when I click on it, my browser still performs a GET request (which fails for obvious reasons):

screenshot of browser network console

I have read on multiple other forum posts, that this might have something to do with jquery not being included. They mentioned you would need to un-comment a line in app/javascript/application.js, however mine is pretty empty:

// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"

These forum posts were also quite old, so I suspect something has changed in the meantime.

Eyeslandic
  • 14,553
  • 13
  • 41
  • 54
Nils
  • 1,755
  • 3
  • 13
  • 25
  • 8
    I have not used hotwired, but does changing `method: :delete` to `data: { turbo_method: :delete }` work? – alexts Dec 24 '21 at 16:49
  • 1
    Yes, this works for me, thanks :) there is only one weird thing: once the DELETE request was performed, my browser is redirected (as desired) but instead of doing a normal GET, it does another DELETE (in my case at "/"). The user doesn't notice it, it just shows up in the network console. – Nils Dec 25 '21 at 15:55
  • Check this github issue and specifically this [comment](https://github.com/hotwired/turbo/issues/288) Maybe the destroy_user_session_path and not specifying delete method fires a request twice... – alexts Dec 25 '21 at 16:05
  • 2
    @Nils - Try adding this `status` in your redirect: `redirect_to action: 'some_action', status: 303`. Because: 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. Also see: https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_to – TomDogg Apr 13 '22 at 15:29
  • For some general clarification, see: https://turbo.hotwired.dev/handbook/drive#disabling-turbo-drive-on-specific-links-or-forms – TomDogg Apr 13 '22 at 15:41
  • What @TomDogg said. I spent over an hour trying to understand why I was getting two redirects. Adding the status: 303 solved it. – Jamie Orchard-Hays Jul 13 '22 at 22:31

5 Answers5

57

As suggested here, the following will suffice:

<%= link_to "Sign Out", destroy_user_session_path, data: { "turbo-method": :delete } %>

I have tested this in my project and it seems to work fine. Thanks also to @alexts, you basically figured this out too, however the comment on GitHub even eliminated the double-request.

Nils
  • 1,755
  • 3
  • 13
  • 25
  • I tried this a few days ago in my project and I could swear it was working. But now when I try this it does not work. – imarg Jan 27 '22 at 00:33
  • Could you post what versions of rails and devise you’re using? – Nils Jan 28 '22 at 08:13
  • This will not work if you place it in the form because it creates another hidden form. The better way of doing it is using `button_to` as stated in the documentation. https://turbo.hotwired.dev/handbook/drive#performing-visits-with-a-different-method – Pavel Oganesyan Jan 29 '22 at 09:47
  • 1
    `button_to` also creates a form. – Nils Jan 30 '22 at 20:46
  • 1
    Hey @Nils, just saw your comment. As I said, I tried this and it did work. Then for some reason it did not and frustrated I searched around and left my comment here. And then, a while later, it worked again. I do not know what I did wrong, what changed, but I was happy it did work and totally forgot about the comment I left. – imarg Feb 13 '22 at 23:28
  • 1
    @imarg : If your `
    ` (or another parent element such as a `
    `) has `data: { turbo: false }` then you will also need to add `turbo: true` to your `link_to`, resulting in: `<%= link_to "Sign Out", destroy_user_session_path, data: { turbo: true, turbo_method: :delete } %>`
    – TomDogg Apr 13 '22 at 15:33
  • this worked for me https://stackoverflow.com/a/74015122/15915143 – Pavan Kumar V Oct 12 '22 at 12:53
  • The problem in using turbo is , it does not reload static js files. – Pavan Kumar V Nov 05 '22 at 11:28
50

There are (at least) two ways to delete something in rails 7:

Using button_to (preferred IMHO):

<%= button_to 'Sign Out', destroy_user_session_path, method: :delete %>

Renders an HTML form which sends a POST request with a hidden _method attribute with 'delete' value. Rails will treat this as if it has a DELETE method (and route it to products#destroy or whatever your routes are saying). Do not use this one within another form (HTML forbids one form inside another).

Using link_to:

<%= link_to 'Sign Out', destroy_user_session_path, data: {turbo_method: :delete} %>

Renders a simple a tag with data-turbo-method attribute. This link sends a real DELETE request.

If your destroy action ends with a redirect_to, some browsers will redirect to a new location with DELETE method (causing errors), so make sure to add status: :see_other parameter to redirect_to, like the guides suggest.

Confirmation

If you want to add confirmation prompt to a button above:

<%= button_to 'Sign Out', destroy_user_session_path, method: :delete,
  form: {data: {turbo_confirm: 'Are you sure?'}} %>

If you want to add confirmation to a link above:

<%= link_to 'Sign Out', destroy_user_session_path,
  data: {turbo_method: :delete, turbo_confirm: 'Are you sure?'} %>
installero
  • 9,096
  • 3
  • 39
  • 43
  • so if we use it inside form, should we use link_to instead button_to or is there any alternatives? ref: https://dev.to/paramagicdev/escaping-the-traditional-rails-form-4c4o – buncis Aug 16 '22 at 06:27
9

Found it on git

Run these commands

It worked for me.

$ rails importmap:install
$ rails turbo:install stimulus:install
Pavan Kumar V
  • 592
  • 6
  • 17
  • 1
    Thanks, it was the missing lines for the rails tutorial to works. I've submitted a PR to improve the documentation with these lines ! – nabellaleen Dec 25 '22 at 17:07
1

method: :delete just add a attribute

in order to make it useful, rails_ujs library is responsible try to include it that can be useful

1

I had a more niche case where I'd turned off turbo globally in the rails 7 app like so:

// app/javascript/application.js
import { Turbo } from "@hotwired/turbo-rails"
Turbo.session.drive = false

If you did that too, you might need to set turbo: true for the button_to approach to work.

Here's what worked for me:

<%= button_to 'Destroy', @page, method: :delete, form: 
  { data: { turbo: true, turbo_confirm: 'Are you sure?' } } %>

It's the same as other answers but it ensures turbo is indeed on for that element.

Notes

  • I didn't need ujs
  • I didn't need jquery or //= require jquery or anything like that.
stevec
  • 41,291
  • 27
  • 223
  • 311