Hotwire: Rails: バックグラウンドで処理したファイルをダウンロードする時のUI

外観

目的
ネイティブアプリを含めて、CSV ファイルや画像ファイルを変換するアプリを何度か作ったことがある。同様のアプリを Hotwire を使って実装してみる。

バッチ処理のダッシュボード画面を作成する。
画面の進捗状況部を Hotwire を用いて更新する。
Action Cable(WebSocket) で通知できるが JavaScript でポーリングする。

2021/10/27 追記
Broadcastable concern 版も作りました。

環境
ruby 3.0.2p107
rails 7.0.0.alpha2

シナリオ
1.利用者は、CSVファイルをアップロードする。
2.システムは、アップロードされたファイルから別のファイルをバックグラウンドで生成する。
3.利用者は、生成されたファイルをダウンロードする。

機能外観
アップロードしたCSVファイルを変換する。
変換処理の進捗状況を画面で確認できる。
変換に成功したらダウンロード用のリンクを画面に表示する。
変換前後のファイルを残す。

画面

画像3

仕様
変換中に別画面に遷移しても変換処理は続ける。今回はルートページとの行き来で確認する。
ファイルの変換には数分(リクエストタイムアウト以上)かかる。今回の実装では数秒のスリープにする。
ファイル名や中身に問題があれば失敗にする。今回の実装では常に成功する疑似処理にする。

処理の状態を(リアルタイムで)画面に表示する。
状態遷移: アップロード待ち => ファイル確認中 => ファイル変換中 => 成功/失敗

画像1

ファイル変換: 今回はアップロードしたファイルを複製するだけにする。

ファイルの永続化に Active Storage を使う。今回は :local を使用する。
バックグラウンド処理に Active Job を使う。今回はデフォルトのバックエンドを使用する。

成功したらダウンロード用のリンクを画面に表示する。

画像2

追加修正した主なファイル

Model
app/models/convert.rb

View
app/views/converts/index.html.erb
app/views/converts/_form.html.erb
app/views/converts/_convert.html.erb
app/views/converts/create.turbo_stream.erb
app/views/converts/status/index.turbo_stream.erb

Controller
app/controllers/converts_controller.rb
app/controllers/converts/status_controller.rb
app/javascript/controllers/reload_controller.js

Router
config/routes.rb

Job
app/jobs/file_convert_job.rb

太字はジェネレータを使用せず追加したファイル

雛形作成

https://github.com/usutani/ui_background_process

gem install rails -v 7.0.0.alpha2 --pre

rails new ui_background_process \
--skip-action-mailbox \
--skip-action-text \
--no-skip-active-storage \
--skip-action-cable \
--skip-jbuilder \
--skip-test \
&& cd ui_background_process

bin/rails active_storage:install
bin/rails db:migrate

bin/rails g scaffold Convert \
status:integer \
message:text

t.integer :status, default: 0, null: false
bin/rails db:migrate

実装

Model
app/models/convert.rb

View
touch app/views/converts/create.turbo_stream.erb
mkdir app/views/converts/status
touch app/views/converts/status/index.turbo_stream.erb

app/views/converts/index.html.erb

app/views/converts/_form.html.erb​

app/views/converts/_convert.html.erb​

app/views/converts/create.turbo_stream.erb​

app/views/converts/status/index.turbo_stream.erb

Router
config/routes.rb

Controller
bin/rails g controller 'converts/status_controller' index
bin/rails g stimulus reload

app/controllers/converts_controller.rb

app/controllers/converts/status_controller.rb

app/javascript/controllers/reload_controller.js

Router
config/routes.rb

Job
bin/rails g job file_convert

app/jobs/file_convert_job.rb

以上です。

この記事が気に入ったらサポートをしてみませんか?