Hotwire: Rails: バックグラウンドで処理したファイルをダウンロードする時のUI: Broadcastable concern 版
外観
目的
Hotwire: Rails: バックグラウンドで処理したファイルをダウンロードする時のUI では、JavaScript でポーリングして画面の処理状態を更新していました。今回は Broadcastable concern で画面を更新したいと思います。
環境
ruby 3.0.2p107
rails 7.0.0.alpha2
macOS 11.6
foreman 0.87.2 (gem install foreman)
Redis server 6.2.5 (brew install redis)
リポジトリ
https://github.com/usutani/ui_background_process_2
雛形作成
モデルやビューなどを作成します。
rails new ui_background_process_2
cd ui_background_process_2
bundle remove jbuilder
bin/rails active_storage:install
bin/rails db:migrate
bin/rails g model Convert status:integer message:text
t.integer :status, default: 0, null: false
bin/rails db:migrate
bin/rails g controller Converts index
config/routes.rb
resources :converts, only: %i[ index create ]
root to: "converts#index"
処理状態の一覧表示
app/models/convert.rb
class Convert < ApplicationRecord
has_one_attached :in_file
has_one_attached :out_file
enum status: {
waiting: 0,
validating: 1,
converting: 2,
succeeded: 3,
failed: 4
}
def status_summary
"#{id}:#{status}"
end
end
db/seeds.rb
c = Convert.new(status: 0, message: 'seed data')
c.in_file.attach(io: File.open('public/404.html'), filename: '404.html')
c.save
bin/rails db:seed
app/views/converts/index.html.erb
<h1>Converts</h1>
<ul>
<div id="converts">
<%= render @converts %>
</div>
</ul>
touch app/views/converts/_convert.html.erb
<%= tag.li id: dom_id(convert) do %>
<%= tag.span convert.status_summary %>
<%= tag.span do %>
<% out_file_path = rails_blob_path(convert.out_file) if convert.out_file.attached? %>
<%= link_to_if(convert.succeeded?, 'Download', out_file_path) { "N/A" } %>
<% end %>
<%= tag.span convert.message %>
<% end %>
app/controllers/converts_controller.rb
class ConvertsController < ApplicationController
def index
@converts = Convert.all
end
end
変換処理モデルの生成
app/views/converts/index.html.erb
<h1>New Convert</h1>
<%= form_with(model: @convert) do |form| %>
<%= form.label :in_file %>
<%= form.file_field :in_file %>
<%= form.submit %>
<% end %>
app/controllers/converts_controller.rb
def index
@converts = Convert.all
@convert = Convert.new
end
def create
@convert = Convert.new(convert_params)
@convert.save
redirect_to converts_url
end
private
def convert_params
params.require(:convert).permit(:in_file)
rescue ActionController::ParameterMissing
nil
end
エラー表示
app/models/convert.rb
validates :in_file, presence: true
app/controllers/converts_controller.rb
def create
@convert = Convert.new(convert_params)
if @convert.save
redirect_to converts_url
else
render :create, status: :unprocessable_entity
end
end
app/views/converts/index.html.erb
<%= form_with(model: @convert) do |form| %>
<div id="error_explanation"></div>
touch app/views/converts/create.turbo_stream.erb
<%= render 'shared/turbo_stream_error_explanation', model: @convert %>
Procfile でサーバーを起動
bin/dev で開始。
Broadcastable concern を使う
app/views/converts/index.html.erb
<%= turbo_stream_from :convert %>
app/models/convert.rb
after_create_commit -> { broadcast_append_later_to :convert }
after_update_commit -> { broadcast_replace_later_to :convert }
app/controllers/converts_controller.rb
if @convert.save
# redirect_to converts_url
行の更新
別ターミナルから状態を更新すると画面も更新される。
bin/rails c
Convert.first.update!(status: :validating)
ジョブ
app/controllers/converts_controller.rb
if @convert.save
FileConvertJob.perform_later(@convert)
bin/rails g job file_convert
以上です。
この記事が気に入ったらサポートをしてみませんか?