@julian from a more conceptual point of view…the answer is it’s just what the web wants us to do. HTML doesn’t natively give us a way for a link to make a POST request, because that’s not what a link is for! The HTML standard says a link is for navigation. When you navigate around the web, you make a series of GET requests. Navigation doesn’t imply you want to do anything while there. Per the HTML standard: “These are links to other resources that are generally exposed…so that the user can cause the user agent to navigate to those resources, e.g. to visit them in a browser or download them.” And that’s why a link will always make a GET request. A GET request is a visit, it says “show me this” and it’s idempotent. When you make the same request it’ll show the same thing.
I think it’s actually semantically incorrect for a link to be anything other than a GET. That’d imply a side-effect (and that, of course, is exactly what you want ujs to do). HTML’s answer for making a request to do something (cause a side effect) is a form.
Now, I understand someone might think this is all a bit academic. We style links to look buttons and sometimes buttons to look like links. It is academic. But it’s analgous to believing, say, a query method in Ruby — def valid?
or something else that ends in a ? — shouldn’t have side effects.
@pgr Presumably you can’t do this:
<%= form_with model: @model do |form| %>
<%# some form %>
<% end %>
<%= button_to "Delete", @model, method: :delete %>
(maybe with a wrapper <div>
or something)? Is that because your button is somewhere in the midde of the form?
If so, you could try putting formmethod
and formaction
attributes on a submit input inside your form. Those will override the action
and method
on the parent form, but only when it’s submitted using that input