モーダル
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-end
ModalDialog#hideOnSuccess()
が実行されますが、event.detail.success
がfalseなので、モーダルは表示されたままになりますサーバサイドバリデーションをする場合は、レスポンスに応じてブラウザ側のUIを出し分ける必要があります。Hotwireの場合はそのロジックを完全にサーバに持たせる方法と、一部分をブラウザに任せる方法があります。UI/UXの要件や設計方針に応じて選択します。