モーダル
Hotwireで作成したモーダルでフォームを送信し、サーバサイドバリデーションが失敗した時の処理を紹介します。下記のビデオのものになります。
form送信が失敗した場合は以下の処理をします
formは表示したままにしますclass TodosController < ApplicationController # ... def update respond_to do |format| if @todo.update(todo_params) flash.now.notice = "Todo was successfully updated." format.turbo_stream else format.turbo_stream { render status: :unprocessable_content} end end end # ... private # ... # Only allow a list of trusted parameters through. def todo_params params.require(:todo).permit(:title) end end
<% if @todo.errors.any? %> <%= turbo_stream.replace "todo-form" do %> <%= render "form", todo: @todo %> <% end %> <% else %> <!-- ... --> <% end %>
updateのActionでリクエストを受け取り、レスポンスを返します。今回はバリエーションが失敗していますので、format.turbo_stream { render status: :unprocessable_content}の方の処理を行います:unprocessable_content(422)とbodyがapp/views/todos/update.turbo_stream.erbに記載のTurbo Streamsになりますif ... elseのifの方だけみます
app/views/todos/_form.html.erb partialがレンダリングされます。これは通常のRailsのバリデーションエラー処理と同じで、入力フォームに@todo.errorsの内容を重ねて表示しますturbo_stream.replace "todo-form"に囲まれていますので、id="todo-form"で指定されたHTML要素(モーダルの中に表示されてform)を置換するように画面が更新されますimport {Controller} from "@hotwired/stimulus" // Connects to data-controller="modal-dialog" export default class extends Controller { // ... hide(event) { this.shownValue = false } hideOnSuccess(event) { if (!event.detail.success) return this.hide(event) } // ... }
form送信が成功するとモーダルが自動的に閉じました。今回もform送信後にturbo:submit-endModalDialog#hideOnSuccess()が実行されますが、event.detail.successがfalseなので、モーダルは表示されたままになりますサーバサイドバリデーションをする場合は、レスポンスに応じてブラウザ側のUIを出し分ける必要があります。Hotwireの場合はそのロジックを完全にサーバに持たせる方法と、一部分をブラウザに任せる方法があります。UI/UXの要件や設計方針に応じて選択します。