60

I'm following Michael Hartl's Rails Tutorial, and for some reason the following code:

<%= link_to 'delete', user, :method => :delete, :confirm => "You sure?",
                                :title => "Delete #{user.name}" %>

Issues a GET request (as I verified by checking the rails server log). I also verified that the following line is in my application view:

<%= javascript_include_tag :all %>

One thing I didn't quite understand, and it's probably the source of my problem: where is the "delete" method defined? I verified in Hartl's source code that he defines a "destroy" method in the controller, not "delete". But even if I change the link_to to :method => :destroy, it just issues a GET.

I'm using Rails 3.1. Any tips?

koggit
  • 613
  • 1
  • 5
  • 6

9 Answers9

80

Also check that this is in your application.js:

//= require jquery
//= require jquery_ujs 

Apparently I had the jquery without the jquery_ujs and I had the same problem until I added that.

Note that you may need to add these lines above any import statements within application.js.

Sam
  • 3
  • 2
Jamel Toms
  • 4,525
  • 2
  • 27
  • 26
56

Most browsers don't actually support the DELETE verb, so Rails fakes it by modifying the HTML it generates. Rails tacks on a HTML5 attribute called data-method and sets it to "delete". So when a user clicks on the link, it is actually issued as a GET request, but the data-method attribute allows for some Rails magic and means your routing code should recognize it as a DELETE request.

edit:

You can test it yourself in the console. Run bundle exec rails c to get into the console, and look at the HTML that this generates:

helper.link_to "delete", "foobar/delete", :method => 'delete'

The HTML should look like this:

<a href="foobar/delete" data-method="delete" rel="nofollow">delete</a>
Jamison Dance
  • 19,896
  • 25
  • 97
  • 99
  • 4
    Thanks, Jergason! This is the HTML that Rails generates for my "delete" -- delete -- everything looks okay, yet when I click this link doesn't delete. I'm using Chrome and typically have no issues with Javascript. Any idea where I could look for the problem? – koggit Sep 19 '11 at 15:30
  • What does your `routes.rb` file look like? – Jamison Dance Sep 19 '11 at 17:10
  • Mine is here: https://github.com/koggit/global2local-interpret/blob/master/config/routes.rb Hartl's is here: https://github.com/railstutorial/sample_app/blob/master/config/routes.rb It looks okay by comparison, though I don't yet understand the routes very well. – koggit Sep 19 '11 at 17:46
  • Can you tell if your UsersController#destroy method is firing when that link is clicked? Stick a print line in or something? – Jamison Dance Sep 19 '11 at 18:21
  • 1
    Thanks for your continued help, Jergason. UserControler#destroy is not firing. I may have located the issue: `Served asset /all.js - 404 Not Found`. It's trying to GET `/assets/all.js`, which doesn't exist. I've Googled for info about this file but didn't come up with much. Any tips for search terms to learn more about all.js in this context? – koggit Sep 19 '11 at 21:01
  • It seems like the Rails UJS stuff is not being included. If you are on Rails 3.1, then you may have some weirdness going on with your asset pipeline. I am not too familiar with that, but you should make sure your assets are being compiled correctly. You could try changing the include tag to `javascript_include_tag :defaults` to see if that helps. – Jamison Dance Sep 19 '11 at 21:19
  • 2
    Thanks-- your response helped me find the keywords to find this post, which has a solution -- http://stackoverflow.com/questions/7281907/rails-3-1-issue-with-javascript-include-tag-in-application-html-erb -- unfortunately, despite working, it's unclear as to **why** this solution. Oh well. :) Thanks again! – koggit Sep 20 '11 at 01:51
  • The button_to solution below was the best way around it for me! – JTE Feb 15 '21 at 10:18
22

You should use the following code

<%= button_to "delete", @user_current, :method => "delete" %>

It will solve the problem or add this line //= require jquery_ujs to application.js and use:

 <%= link_to 'delete', user, :method => :delete, data: {:confirm => "You sure?" } ,
                            :title => "Delete #{user.name}" %>
thumbtackthief
  • 6,093
  • 10
  • 41
  • 87
Hien Luong
  • 510
  • 1
  • 4
  • 15
6

As browsers don't support the DELETE verb, Rails creates a workaround for this problem by simulating a DELETE request through a standard GET or POST. The way method: :delete works is with a JavaScript handler for all links with data-method="delete" which modifies the request so Rails processes it as a DELETE. This JavaScript handler is provided by the jquery_ujs library.

There are several things that could have gone wrong:

  1. Make sure you have both jquery and jquery_ujs included in your application.js. Without both nothing will process the data attributes.
  2. Make sure the link in question really has the method: :delete option specified.
  3. Make sure for some reason you haven't stopped the event propagation of the link in question, like so for example:
$( 'a' ).click( function( event ) {
    event.stopPropagation()
})

As this would prevent the jquery_ujs handlers from being executed and the request will never be modified and will remain just a standard GET.

Itay Grudev
  • 7,055
  • 4
  • 54
  • 86
2

I faced the same problem with Michael's tutorial. The data-method="delete" actually works as expected - it does call the destroy action in the controller. The reason it tries to GET (and eventually fail) is the following:

You'll notice that one of the before_filter's in the controller is set to signed_in_user, and in session_helper.rb, you'll notice that signed_in_user calls store_location (private method), which updates session[:return_to] to the current URL.

So, back in your controller's destroy action, it tries to redirect_back_or which results in GET current_url. I modified the signed_in_user helper to only call store_location when user is not signed in already.

Undo
  • 25,519
  • 37
  • 106
  • 129
Brij
  • 93
  • 1
  • 4
1

On rails 5 :

Have the same problem, all 'DELETE' posts were compromised, affecting my crud pages AND devise signout... to solve the problem all I had to do was :

//= require rails-ujs

0

All we need is add the below line of code

//= require jquery_ujs 

It seems like a bug:))

giapnh
  • 2,950
  • 24
  • 20
0

You want to do this in Rails 6+:

 link_to(
  'Delete Me',
   some_controller_path(model),
   data: { method: :delete }
 )
Martin Streicher
  • 1,983
  • 1
  • 18
  • 18
0

Use button_to instead of link_to.

blackgreen
  • 34,072
  • 23
  • 111
  • 129