Skip to content

Commit 89bcc96

Browse files
authored
Handle conversation form errors via Turbo Stream (#1006)
## Summary - Add Turbo Stream error handling to conversation creation failures - Show validation messages in `form_errors` frame - Enhance Stimulus form validation controller to render server-side errors on 422 responses ## Testing - `bundle exec rubocop` *(fails: command not found)* - `bundle exec brakeman -q -w2` *(fails: command not found)* - `bundle exec bundler-audit --update` *(fails: command not found)* - `bin/codex_style_guard` *(fails: command not found)* - `bin/ci` *(fails: command not found)* ------ https://chatgpt.com/codex/tasks/task_e_689b64c801a483219d5c496b53f5584f
2 parents b0fe7e4 + 3e137f8 commit 89bcc96

File tree

4 files changed

+27
-5
lines changed

4 files changed

+27
-5
lines changed

app/controllers/better_together/conversations_controller.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def new
2020
authorize @conversation
2121
end
2222

23-
def create # rubocop:todo Metrics/MethodLength
23+
def create # rubocop:todo Metrics/MethodLength, Metrics/AbcSize
2424
@conversation = Conversation.new(conversation_params.merge(creator: helpers.current_person))
2525

2626
authorize @conversation
@@ -33,7 +33,12 @@ def create # rubocop:todo Metrics/MethodLength
3333
format.html { redirect_to @conversation }
3434
end
3535
else
36-
render :new
36+
respond_to do |format|
37+
format.turbo_stream do
38+
render :create_error, status: :unprocessable_entity
39+
end
40+
format.html { render :new, status: :unprocessable_entity }
41+
end
3742
end
3843
end
3944

app/javascript/controllers/better_together/form_validation_controller.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Controller } from "@hotwired/stimulus";
2+
import { Turbo } from "@hotwired/turbo-rails";
23

34
export default class extends Controller {
45
static targets = ["input"];
@@ -19,13 +20,15 @@ export default class extends Controller {
1920

2021
// Handle form submission
2122
this.element.addEventListener("submit", this.handleFormSubmit.bind(this));
23+
this.element.addEventListener("turbo:submit-end", this.handleSubmitEnd.bind(this));
2224

2325
// Handle Turbo navigation (unsaved changes warning)
2426
document.addEventListener("turbo:before-visit", this.handleTurboNavigation.bind(this));
2527
}
2628

2729
disconnect() {
2830
document.removeEventListener("turbo:before-visit", this.handleTurboNavigation.bind(this));
31+
this.element.removeEventListener("turbo:submit-end", this.handleSubmitEnd.bind(this));
2932
}
3033

3134
storeInitialValues() {
@@ -59,6 +62,18 @@ export default class extends Controller {
5962
this.isSubmitting = true;
6063
}
6164

65+
async handleSubmitEnd(event) {
66+
const { success, fetchResponse } = event.detail;
67+
68+
if (!success && fetchResponse?.response.status === 422) {
69+
const html = await fetchResponse.responseHTML;
70+
Turbo.renderStreamMessage(html);
71+
this.isSubmitting = false;
72+
} else if (success) {
73+
this.resetValidation();
74+
}
75+
}
76+
6277
handleTurboNavigation(event) {
6378
if (this.isFormDirty() && !this.isSubmitting) {
6479
const confirmation = confirm("You have unsaved changes. Are you sure you want to leave?");
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<%= turbo_stream.update 'form_errors', partial: 'layouts/better_together/errors', locals: { object: @conversation } %>

app/views/better_together/conversations/new.html.erb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
<h6 class="mb-0"><%= t('.new_conversation') %></h6>
55
</div>
66

7-
<div class="card-body">
8-
<%= form_with(model: @conversation, local: true, data: { turbo: false, controller: 'better_together--form-validation'}) do |form| %>
9-
<div class="mb-3">
7+
<div class="card-body">
8+
<%= form_with(model: @conversation, data: { controller: 'better_together--form-validation' }) do |form| %>
9+
<%= turbo_frame_tag 'form_errors' %>
10+
<div class="mb-3">
1011
<%= form.label :participant_ids, t('.add_participants') %>
1112
<%= form.collection_select :participant_ids, available_participants, :id, :select_option_title, { }, { multiple: true, class: 'form-select', required: true, data: { controller: "better_together--slim-select" } } %>
1213
</div>

0 commit comments

Comments
 (0)