4

It is my understanding that the HTTP verb 'DELETE' is not supported in HTML, and as such a different route is required when making delete forms.

If this is the case, why does this code works fine,

<%=button_to 'Delete', {:controller => :users, :action => 'destroy', :id => user.id}, :method => :delete%>

but, following code doesn't work

<%=button_to 'Delete', {:controller => :users, :action => 'destroy', :id => user.id}%>

and it gives the error: 'No route matches [POST] "users/1/"'

shouldn't the url this resolves to be users/destroy/1 ?

Saqib Shahzad
  • 982
  • 12
  • 28
A S-R
  • 66
  • 6

4 Answers4

1

Sounds like you don't need a code answer, since you've already got a working version. Rails does a bunch of stuff behind the scenes, so it can be hard to know what exactly is happening in the browser unless you go inspect it.

DELETE may not work as a property in an HTML <form> tag, but it's still a valid HTTP request.

Are the PUT, DELETE, HEAD, etc methods available in most web browsers?

What is the usefulness of PUT and DELETE HTTP request methods?

Ken
  • 672
  • 1
  • 6
  • 14
  • I understand that they are valid HTTP verbs, and while you are correct that I have a working code solution, it doesn't sit well to use code I don't understand. Are you familiar with any documentation on how :method=>:delete works? I wasn't able to find a question that addressed this or the documentation surrounding its behaviors (both the documentation for url_for and button_to weren't much help) – A S-R Oct 20 '18 at 21:21
  • 1
    Super respect your desire to know everything that's going on. But if you do that for everything in Rails, you're gonna spend a lot of time understanding idioms that try to make your life "easier". It is, I think a both a strength and a flaw of Rails that so much is done behind the scenes. It makes it great for prototyping, but difficult for customization. At some point you have to either go with it, or go with a different system. Either that or you'll end up as a Rails contributor. :) – Ken Oct 20 '18 at 22:08
1

The older versions of HTML supports only GET and POST. The newer version includes PUT, PATCH, and DELETE which are treated as XHR(XMLHttpRequest) requests or simply AJAX requests by all major web browsers.

When the requests for PUT or PATCH or DELETE are made, Rails under the hood, with the help of Javascript processes these requests as XHR requests to the client. When the Javascript in your application is not working or disabled, these requests will fall back to GET

Now coming back to your code snippet which is not working. You have the below

<%= button_to 'Delete', {:controller => :users, :action => 'destroy', :id => user.id}%>

button_to by default creates a form and sends the request as POST, unless if you are explicitly overriding it, as you are doing in the first case with :method => :delete. So the above code snippet generates a url like users/1/, but as a POST which eventually fails as you don't have any such route defined in the routes.rb

Shouldn't the url this resolves to be users/destroy/1 ?

No, when you use :method => :delete in your code, the url that is generated will be users/1 but the request is sent as DELETE, which eventually works as it is a valid request according to your routes that are defined in routes.rb

Pavan
  • 33,316
  • 7
  • 50
  • 76
0

It is rails convention to mention the method (HTTP verb) with the link, so that Rails knows which controller method to call, because without the HTTP verb 3 actions show, update and destroy, all of these 3 generate the same url path that is "/users/:id" (if controller is "UsersController"). For further reading, I suggest to have a look at:

https://guides.rubyonrails.org/routing.html#crud-verbs-and-actions

EDIT:

As you can see in the screenshot, if you set the HTTP Verb to DELETE, Rails will automatically know that it has to run the destroy action, otherwise, the path for show,update and destroy is same.

enter image description here

Saqib Shahzad
  • 982
  • 12
  • 28
  • I was under the impression that button_to will default to post, but even if it doesn't I have verified that :method=>:post doesn't work. I'm curious as to what rails is doing behind the scenes to emulate a form with a DELETE HTTP verb – A S-R Oct 20 '18 at 21:25
  • i have updated my answer, and go through the link I mentioned, it will definitely answer your question. – Saqib Shahzad Oct 20 '18 at 21:33
  • I don't think you understand exactly what I'm asking. I understand that routing works by pairing HTTP verbs with the url, and I understand that rails can infer which controller method to call based on the combination of HTTP verbs and the url, but you cannot use method="delete" with an html form. I am asking how rails emulates this behavior using the :method=>:delete hash. – A S-R Oct 20 '18 at 21:37
0

Putting :method=>:delete signals Rails to create the form with hidden values that it will then use to emulate the function of a form with

method="delete"

If anyone would be able to explain why removing :action => :destroy causes :id => user.id to be treated as a key and value in the url (i.e. users?id=1 instead of users/1 ) I'd be grateful.

A S-R
  • 66
  • 6
  • It looks like it's falling back to a GET method – Ken Oct 20 '18 at 22:03
  • I believe it's because in this case, you are explicitly setting `:id => user.id`, which will automatically be parameterized to send with the URL. I think what you'd want is `<%= button_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %>`.Rails inferes the Controller type from the Active Record variable `user` (assumes that the Controller matches the Model) and no id needs to be set because `user` already carries it. – Devin Oct 20 '18 at 22:15