<% if @project.errors.any? %>
<%= turbo_stream.replace dom_id(@project, :form), partial: "projects/form", locals: { project: @project } %>
<% else %>
<%= turbo_stream.replace dom_id(@project), partial: "projects/project", locals: { project: @project } %>
<%= turbo_stream.update "flash", partial: "shared/flash" %>
<% end %>
class ProjectsController < ApplicationController
def update
@project = Project.find(params[:id])
if @project.update(project_params)
respond_to { |f| f.turbo_stream; f.html { redirect_to @project, notice: 'Saved.' } }
else
respond_to do |f|
f.turbo_stream { render :update, status: :unprocessable_entity }
f.html { render :edit, status: :unprocessable_entity }
end
end
end
end
Hotwire forms feel “native” when invalid submissions keep you in context. Replace just the form frame with errors and keep the rest of the page intact. Return 422 so clients and caches behave correctly.