Hotwire Discussion

Simple form not getting replaced

Hello there,

I am having a hard time figuring out what I am doing wrong while trying to re-display a form with errors using turbo.

I made it very simple to take out unnecessary complexity, here are the main components: view, partial, controller and response after the form has been submitted.

When visiting the /show page in my app, the server renders the following view:

<p>Post message as <%= current_user.name %>:</p>
<%= render 'form' %>

The form partial contains the id to be replaced by the turbo stream (create-form):

<div id="create-form">
   <%= @error %>
   <%= form_with url: '/messages' do |f| %>
      <div class="form-group">
        <%= f.text_area :content, placeholder: 'Enter a message', class: 'form-control',  rows: 3 %>
      </div>

      <div class="actions">
        <%= f.submit class: "btn btn-primary" %>
      </div>
   <% end %>
</div>

Here is my controller code.

  def create
      if params[:content] == "A"
          @error = "An error"
          render turbo_stream: turbo_stream.replace("create-form", partial: 'form')
      end
  end

However, when I submit the form with the parameter that should trigger the form to be re-rendered by turbo, I get a 200 status code, with the following response:

<turbo-stream action="replace" target="create-form">
   <template>
       <div id="create-form">
       An error
       <form action="/traveller/conversations" accept-charset="UTF-8" data-remote="true" method="post">
          <input type="hidden" name="authenticity_token" value="5JZYzkAyegULvdip/wwP9KOCYAyL3aTQtealVOCdxfz7lF7qJonMhR+VSHAmcZnRP/mVnM4n1osFfC8rxCfang==" />
          <div class="form-group">
              <textarea placeholder="Enter a message" class="form-control" rows="3" name="content" id="content">
              </textarea>
          </div>

          <div class="actions">
              <input type="submit" name="commit" value="Save " class="btn btn-primary" data-disable-with="Save " />
          </div>
        </form>
      </div>
    </template>
 </turbo-stream>
 <div id="console" data-mount-point='/__web_console'
    data-session-id='71a1b75a63242f663a332e5009ed49fe'
     data-prompt-label='>> '>
 </div>
 <script type="text/javascript" data-template="console" nonce=""> (function() { 
 ....
</script>

It seems the server replies with the right partial but unfortunately the form never gets updated.

What am I missing? Or I am just not understanding how turbo streams works?

Thanks

1 Like

Nothing stands out. It should be working.

Try adding status: :accepted to your render:

 def create
      if params[:content] == "A"
          @error = "An error"
          render turbo_stream: turbo_stream.replace("create-form", partial: 'form'), status: :accepted
      end
  end

Turbo Handbook talks about not being able to handle non-200 responses from forms a bit.

I’m having the same issue, but with a datalist. Is there a programatic way to check if turbo stream is loaded and working on the frontend?

I tried hooking up some console logs to the turbo:render and turbo:before-stream-render events, and they are not firing.

document.addEventListener('turbo:before-stream-render', function(e) {
  console.log("Turbo stream will render")
})

document.addEventListener('turbo:render', function(e) {
  console.log("Turbo stream should have rendered")
})

Edit:
After searching a little bit more, I narrowed it down to this: Document Turbo Stream Accept: header changes by seanpdoyle · Pull Request #40 · hotwired/turbo-site (github.com).

Apparently, turbo streams does not support GET requests. So my problem is different from the problem of the OP.