class CommentsController < ApplicationController
def create
@post = Post.find(params[:post_id])
@comment = @post.comments.build(comment_params.merge(author: current_member))
if @comment.save
respond_to do |format|
format.turbo_stream
format.html { redirect_to @post, notice: 'Comment posted.' }
end
else
respond_to do |format|
format.turbo_stream { render :create, status: :unprocessable_entity }
format.html { redirect_to @post, alert: 'Fix the errors.' }
end
end
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
<%= turbo_stream.prepend dom_id(@post, :comments) do %>
<%= render @comment %>
<% end %>
<%= turbo_stream.replace dom_id(@post, :comment_form) do %>
<%= render 'comments/form', post: @post, comment: Comment.new %>
<% end %>
Action Text is great, but you need to be deliberate about how you render it in a Turbo-powered UI. I keep the comment form inside a turbo_frame_tag so it can be replaced on validation errors (still 422). On success, I clear the form by replacing the frame with a fresh form partial, and I prepend the rendered comment to the list. The controller doesn’t have to know about the editor details; it’s still a normal comment_params permitting :body. One thing I watch for is loading Trix assets correctly (importmap or bundler). Once it’s set up, this approach gives you rich text with minimal custom JS.