Hello!
I am roughly following an example I found here and running into some issues: ChatGPT streaming with ruby-openai, Rails 7, Hotwire, Turbostream, Sidekiq and Tailwind! · GitHub (a major difference is I have a model and controller callled ChatMessage not just Message and my Model has a field called message in place of content)
I’m currently having an issue where submitting the form causes the browser to redirect to the Turbo stream response (as plain text) instead of placing it in the frame. I think this is because Turbo is not adding text/vnd.turbo-stream.html to the Accept request header when submitting the form or it is not interrupting the form/preventing default handling. Rails correctly responds with a text/vnd.turbo-stream.html response.
I can’t figure out/find documentation for how to really debug or log anything with Turbo in the browser/JavaScript side. I can confirm that Stimulus is working fine elsewhere in my app (so JS is loading), and Turbo-based navigation/redirects between pages (the default functionality from Rails scaffold that doesn’t require additional setup) is working fine.
I have a form that looks like:
<%= turbo_frame_tag "#{dom_id(chat)}_chat_message_form" do %>
<%= form_with(model: ChatMessage.new, url: chat_chat_messages_path(format: :turbo_stream)) do |form| %>
<div class="my-5">
<%= form.text_area :message, rows: 4, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full", autofocus: true, "x-on:keydown.cmd.enter" => "$event.target.form.requestSubmit();" %>
</div>
<div class="grid justify-items-end">
<%= form.button type: :submit, class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" do %>
<i class="fas fa-paper-plane"></i>
<span class="pl-2">Send</span>
<% end %>
</div>
<% end %>
<% end %>
I needed to change the URL from url: [chat, chat.chat_messages.new] to chat_chat_messages_path(format: :turbo_stream) or I would get an ActionController::UnknownFormat error from Rails.
I tried adding data: {turbo_stream: true} or data: {turbo_stream: true, turbo_frame: "#{dom_id(chat)}_chat_message_form"} to the form_with to no effect.
Rails 7.1.1 turbo-rails 1.5.0 @hotwired/turbo-rails 7.3.0
Controller:
class ChatMessagesController < ApplicationController
include ActionView::RecordIdentifier
before_action :authenticate_user!
def create
@chat_message = ChatMessage.create(chat_message_params.merge(chat: Chat.user_last_chat(current_user), role: "user"))
GetAiResponse.perform_later(@chat_message.chat_id)
respond_to do |format|
format.turbo_stream
end
end
private
def chat_message_params
params.require(:chat_message).permit(:message)
end
end
create.turbo_stream.erb:
<%= turbo_stream.append "#{dom_id(@chat_message.chat)}_chat_messages" do %>
<%= render "chat_message", chat_message: @chat_message, scroll_to: true %>
<% end %>
<%= turbo_stream.replace "#{dom_id(@chat_message.chat)}_chat_message_form" do %>
<%= render "form", chat: @chat_message.chat %>
<% end %>
routes.rb:
resource :chat, only: [:create, :new, :current_chat], as: :current_chat do
member do
# Some other paths here as well
resources :chat_messages, only: [:create], as: :chat_chat_messages
end
end
I’m really stumped on this! Any help is much appreciated!