33 · side path · forms

Post an empty message.

The server does what a lot of Rails code does on a validation failure: render :index with the errors, status 200. Watch: the response arrives, and Turbo ignores it. The page doesn't change. The console explains.

Place your bet before you read on: why would Turbo refuse a perfectly good HTML response?

→ clear the box and press Post
33 · the rule

After a POST, a 200 has to be a redirect.

If Turbo rendered that 200, the page would be sitting at a URL that was reached by POST. A refresh would re-POST, and browsers show the "resubmit form?" dialog for exactly that reason. Turbo can't replicate that dialog, so it refuses the situation instead. (303 rather than 302 because a 303 always means "now GET this", even after a PATCH or DELETE.)

Errors are still allowed to render. They just have to say they're errors:

if @message.save
  redirect_to messages_path, status: :see_other      # 303
else
  render :new, status: :unprocessable_content   # 422
end

Flip the server to 422 and post empty again. The page renders with the errors, and the URL stays put.

→ switch, post empty
33 · the rest of the form story

Small things Turbo does to forms.

  • The submitter is disabled from turbo:submit-start to turbo:submit-end. No double posts. data-turbo-submits-with="Saving…" swaps its label meanwhile.
  • data-turbo-confirm on a form or a data-turbo-method link asks first. Replace the browser dialog with Turbo.config.forms.confirm = yourFunction.
  • GET forms (search boxes) navigate like links. Point one at a frame with data-turbo-frame and it filters in place; add data-turbo-action="advance" to put the query in the URL.