Skip to content

Update getting started guide to use button_to when deleting articles and comments#43430

Closed
stuart-leitch wants to merge 3 commits intorails:mainfrom
stuart-leitch:main
Closed

Update getting started guide to use button_to when deleting articles and comments#43430
stuart-leitch wants to merge 3 commits intorails:mainfrom
stuart-leitch:main

Conversation

@stuart-leitch
Copy link
Copy Markdown

Rails 7 doesn't support UJS by default so destroys / deletions need to use Turbo Drive instead.

See #43429 - Edge guide 'Getting Started' has errors where we're deleting articles and comments.

This PR removes references to UJS and explicitly mentions Turbo Drive for submitting DELETE requests. Confirmation of these operations is now not applied.

A further issue appeared where following a DELETE a redirect_to directive seems to retain the previous verb ('DELETE' in this case. This was leading to an attempted DELETE on the root_path after deleting the article. As such the redirect_to has been specified to use the HTTP status 303.

This is a documentation only change.

@ghiculescu, as per your nudge ;-)

@ghiculescu
Copy link
Copy Markdown
Member

Thanks so much for going through the guide so thoroughly!

I think this has also highlighted some places where the Turbo <> Rails integration could improve. @dhh what do you think about the turbo-rails gem supporting method: on links the same way UJs did (but with the right attribute)?

The need for a 303 sounds like a bug in Turbo 🤔

@dhh
Copy link
Copy Markdown
Member

dhh commented Oct 12, 2021

I'd actually prefer to let method: fade away. It's too tight of an integration with a front-end setup, and I think it's bad practice anyway that we shouldn't encourage.

@dhh
Copy link
Copy Markdown
Member

dhh commented Oct 12, 2021

There's no need for 303 when doing normal redirects with Turbo. Not sure where that's coming from.

Comment thread guides/source/getting_started.md Outdated
@ghiculescu
Copy link
Copy Markdown
Member

I'd actually prefer to let method: fade away. It's too tight of an integration with a front-end setup, and I think it's bad practice anyway that we shouldn't encourage.

Hmm, maybe we should suggest button_to in the getting started guide and not rely on any JS?

@stuart-leitch
Copy link
Copy Markdown
Author

There's no need for 303 when doing normal redirects with Turbo. Not sure where that's coming from.

I think it's related to this: https://turbo.hotwired.dev/handbook/drive#redirecting-after-a-form-submission. I can understand why turbo will reject a 200 response after a stateful response, and a 303 is probably the correct status to ensure that the following request is issued as a GET.

So maybe the server has to be explicit about making the redirect a 303. Not sure if redirect_to can tell that it's responding to a stateful request and therefore use a 303?

Should 303 be the default, rather than a 302? And we can then be explicit when wanting to maintain the previous method? This feels like a less common occurrence. Maybe I'm missing something.

@stuart-leitch
Copy link
Copy Markdown
Author

I'd actually prefer to let method: fade away. It's too tight of an integration with a front-end setup, and I think it's bad practice anyway that we shouldn't encourage.

Hmm, maybe we should suggest button_to in the getting started guide and not rely on any JS?

I think this is probably the right way to go. Buttons rather than links for actions; probably sensible to use that good practice in the guide. I'll have a go and update the PR.

@stuart-leitch
Copy link
Copy Markdown
Author

Update pushed to use button_to rather than link_to.

Can't find any way to retain the confirmation which UJS previously handled (without adding distracting complication).

@stuart-leitch stuart-leitch changed the title Updated to use data-turbo-method for deleting articles and comments Update getting started guide to use button_for when deleting articles and comments Oct 12, 2021
@fschwahn
Copy link
Copy Markdown
Contributor

There's no need for 303 when doing normal redirects with Turbo. Not sure where that's coming from.

@dhh there was a discussion about this in the PR that added data-turbo-method support, but it happened after it was already merged: hotwired/turbo#299 (review) . Maybe @Intrepidd know more?

@Intrepidd
Copy link
Copy Markdown
Contributor

There's no need for 303 when doing normal redirects with Turbo. Not sure where that's coming from.

@dhh there was a discussion about this in the PR that added data-turbo-method support, but it happened after it was already merged: hotwired/turbo#299 (review) . Maybe @Intrepidd know more?

AFAIK a simple redirection on a DELETE form submission will try to perform the redirect with the DELETE method, returning a 303 is necessary for the subsequent request to be a GET

@dhh
Copy link
Copy Markdown
Member

dhh commented Oct 13, 2021

Ah, I see, this is specifically about data-turbo-method. We should follow the old style where we do POST with a _method, then, for data-turbo-method. Anyone want to whip up a PR for that?

@Intrepidd
Copy link
Copy Markdown
Contributor

Intrepidd commented Oct 13, 2021

Ah, I see, this is specifically about data-turbo-method. We should follow the old style where we do POST with a _method, then, for data-turbo-method. Anyone want to whip up a PR for that?

You mean change turbo so data-turbo-method always sends a POST request with the real method under _method ?

AFAIK _method is a rails construct so if the backend is anything different the results are going to be unexpected

@dhh
Copy link
Copy Markdown
Member

dhh commented Oct 13, 2021

I guess one thing we could do is have Turbo ship with a default implementation that uses "real" DELETEs, which then requires the use of 303 instead of 302, and then have turbo-rails override that implementation to do the POST w/ _method setup.

Because we can't change the default return value of redirect_to in Rails. It's a pain to have to remember when to use 303. This should just work out of the box.

@stuart-leitch
Copy link
Copy Markdown
Author

The 303 isn't required when using button_to to achieve the delete, only when using link_to.

So I've removed the 303 response in this PR now that it's using button_to.

On the larger issue of link_to deletes requiring a 303 response, should changing the method be supported at all? I'm trying to work out when that's a sensible thing to do?

@dhh
Copy link
Copy Markdown
Member

dhh commented Oct 13, 2021

Yeah because button_to creates a form that uses the POST/_method way of setting DELETE. Whereas link_to with data-turbo-method will actually set the "real" method to DELETE. Which isn't compatible with 302. Anyway, I think we should be promoting button_to in any case.

But then we should also fix data-turbo-method in turbo-rails such that it uses POST/_method, such that if you do use it, it'll work the same as all the other ways of doing remote requests. And be backwards compatible with the UJS expectations.

Comment thread guides/source/getting_started.md Outdated
Comment thread guides/source/getting_started.md Outdated
@stuart-leitch
Copy link
Copy Markdown
Author

Just checking my understanding...

link_to will create an tag in the markup with a data-turbo-method attribute. When the link is clicked turbo will intercept this to use a DELETE, except if it's turbo-rails, in which case it will use a POST with an attribute that tells Rails to interpret the POST as a DELETE.

I'm sure that can work, but seems like a lot going on to make a link do something it's not really supposed to do.

Alternatively is it possible for 'redirect to' in Rails to examine the request it's responding to, and send a 303 if the request is a delete?

@dhh
Copy link
Copy Markdown
Member

dhh commented Oct 13, 2021

I think that's the correct understanding, Stuart. I don't see how we could distinguish a Turbo DELETE from a API DELETE and do something custom in that case. I also think it'd be more confusing to do it like this.

Turbo already has a plugin option for -confirm, where users can supply their own method. We can use the same approach here.

@stuart-leitch
Copy link
Copy Markdown
Author

Turbo already has a plugin option for -confirm, where users can supply their own method. We can use the same approach here.

I'm maybe being a bit dense, apologies if so. I can't see a (turbo) way to do the dialog to confirm deletion, without adding a stimulus controller. That feels like a distraction for the getting started guide. Any pointers appreciated...

@stuart-leitch
Copy link
Copy Markdown
Author

I guess one thing we could do is have Turbo ship with a default implementation that uses "real" DELETEs, which then requires the use of 303 instead of 302, and then have turbo-rails override that implementation to do the POST w/ _method setup.

Because we can't change the default return value of redirect_to in Rails. It's a pain to have to remember when to use 303. This should just work out of the box.

Think this is a separate issue to the problem in the getting started guide. I've created an issue in turbo-rails to cover this: hotwired/turbo-rails#259

@stuart-leitch
Copy link
Copy Markdown
Author

Hey folks, (@dhh, @ghiculescu, @Intrepidd, @fschwahn)

Looking for a bit of guidance on this PR.

The (edge) getting started guide is currently broken, this PR fixes that by switching to button_to rather than link_to. The downside is that we lose the confirmation on-delete. I see that a PR is in progress to add data-turbo-confirm, but think it's due in Rails 7.1.0.

So, shall we park this until the turbo confirm functionality is available, or go with it as is, and add a new issue to re-add confirmation once 7.1.0 is released.

Again, sorry if I'm missing something... Thanks for the help in getting here, I've learned an absolute ton 😄 .

@stuart-leitch stuart-leitch changed the title Update getting started guide to use button_for when deleting articles and comments Update getting started guide to use button_to when deleting articles and comments Oct 16, 2021
@ghiculescu
Copy link
Copy Markdown
Member

My opinion is we should go with this and update the docs again when data-turbo-confirm lands.

@dhh
Copy link
Copy Markdown
Member

dhh commented Oct 18, 2021

data-turbo-confirm has been merged to turbo and will be part of a release any day now 👍

@jean-francois-labbe
Copy link
Copy Markdown
Contributor

I'm getting a silent bug/behaviour when changing my link_to method: :delete to button_to method: :delete.
I have forms with a submit button and links inside it, for example a link to: delete the element, delete images attached to the element.

<%= form_with(url: '/', authenticity_token: false) do |form| %>
  <div class="mb-4 text-right">
    <%= link_to "delete image", "/car/1/image", method: :delete %>
    <%= form.submit %>
  </div>
<% end %>

It was working fine with turbolinks and rails 6.1.
With Hotwire and rails 6.1 it is not working.
So I changed my link_to to button_to.

<%= form_with(url: '/', authenticity_token: false) do |form| %>
  <div class="mb-4 text-right">
  </div>
    <%= button_to "delete image", "/car/1/image", method: :delete %>
    <%= form.submit %>
  </div>
<% end %>

The page is rendered, the button is here, it has a form around it (as expected).

But a form inside a form is invalid.

When viewing the raw html I can see the form around the button.
When inspecting the button with Chrome dev tool, I can see that the form is missing around the button.
More precisely, that Chrome removed the form around the button.

When the button is clicked it will post the main form, it will not perform the button action.

The fact that a form inside a form is invalid is documented. But rails generated the html without warning.
Should we keep this behaviour or print a warning ?

I guess users could fall into this trap.

I'm confused as to how I should use buttons or links.
Buttons will cause me trouble as I'll have to move them outside the form and change the layout.

@dwightwatson
Copy link
Copy Markdown
Contributor

@jean-francois-labbe while nested forms won't work, there may be a workaround that could keep the button in place but still work. There's the form attribute that can be placed on the button that could point it to submit another form with that name, and has good support outside of IE.

The pain point is that the form would need to be rendered elsewhere while the button still goes where you put it. I doubt the button_to method would ever be updated to work with that magic.

However, this same problem has bitten me too, especially with the DELETE/DELETE redirect.

@svandragt
Copy link
Copy Markdown

svandragt commented Dec 16, 2021

I got stuck trying out Rails 7 because of this issue, I noticed that @stuart-leitch PR is passing the article id to the id parameter, this is not required and instead the instance variable can be passed to the button, which looks a bit more elegant:

<li><%= button_to "Destroy", @article, method: :delete %></li>

@rafaelfranca
Copy link
Copy Markdown
Member

Thank you for the pull request. Closed by #43941

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants