Hotwire: Broadcastable concern の修作
外観
目的
Action Cableの習作: stream_fromとbroadcast_to を 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)
参照
Turbo Handbook / Integration with Server-Side Frameworks
broadcastable.rb
リポジトリ
https://github.com/usutani/try_hw_simple_broadcast
画面
雛形作成
rails new try_hw_simple_broadcast
cd try_hw_simple_broadcast
bundle remove jbuilder
bin/rails g model Message body
bin/rails db:migrate
bin/rails g controller Messages index
config/routes.rb
resources :messages, only: %i[ index create]
root to: "messages#index"
db/seeds.rb
Message.create([{ body: "Hello" }, { body: "こんにちは" }])
bin/rails db:seed
メッセージ一覧
app/controllers/messages_controller.rb
def index
@messages = Message.all
@message = Message.new
end
app/views/messages/index.html.erb
<div id="messages">
<%= render @messages %>
</div>
touch app/views/messages/_message.html.erb
<div>
<%= message.body %>
</div>
メッセージ作成
app/controllers/messages_controller.rb
def create
@message = Message.new(message_params)
if @message.save
redirect_to messages_url
else
@messages = Message.all
render :index, status: :unprocessable_entity
end
end
private
def message_params
params.require(:message).permit(:body)
end
app/views/messages/index.html.erb
<div id="messages">
<%= render @messages %>
</div>
<%= form_with model: @message do |form| %>
<%= form.text_field :body %>
<%= form.submit %>
<% end %>
以上で準備完了。
Procfile でサーバーを起動する。
foreman で Rails / Redis サーバーを起動する
bin/dev で開始。
作成したメッセージを turbo_stream で追加
def create
@message = Message.new(message_params)
if @message.save
respond_to do |format|
format.turbo_stream
format.html { redirect_to messages_url }
end
else
@messages = Message.all
render :index, status: :unprocessable_entity
end
end
touch app/views/messages/create.turbo_stream.erb
<%= turbo_stream.append "messages", @message %>
touch app/views/messages/index.turbo_stream.erb
Messageモデルでbroadcastする
app/views/messages/index.html.erb
<%= turbo_stream_from :message %>
app/models/message.rb
class Message < ApplicationRecord
after_create_commit :broadcast_later
private
def broadcast_later
broadcast_append_later_to :message
end
end
rm app/views/messages/create.turbo_stream.erb
rm app/views/messages/index.turbo_stream.erb
app/controllers/messages_controller.rb
def create
@message = Message.create(message_params)
end
エラー表示
app/models/message.rb
class Message < ApplicationRecord
after_create_commit :broadcast_later
validates :body, length: { minimum: 2 }
private
def broadcast_later
broadcast_append_later_to :message
end
end
touch app/views/messages/create.turbo_stream.erb
<% if @message.errors.any? %>
<%= turbo_stream.update :error_explanation do %>
<h2><%= pluralize(@message.errors.count, 'error') %> prohibited this message from being saved:</h2>
<ul>
<% @message.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
<% end %>
<% else %>
<%= turbo_stream.update :error_explanation, '' %>
<% end %>
app/views/messages/index.html.erb
<%= turbo_stream_from :message %>
<div id="messages">
<%= render @messages %>
</div>
<div id="error_explanation"></div>
<% form_data = { controller: "reset-form", action: "turbo:submit-end->reset-form#reset" }%>
<%= form_with model: @message, data: form_data do |form| %>
<%= form.text_field :body %>
<%= form.submit %>
<% end %>
補足
先にコントローラーに書いて疎通確認しても良いかも。
def create
@message = Message.new(message_params)
if @message.save
@message.broadcast_append_later_to "message"
end
end
stimulus reset_form フォームのリセット
但しこの方法ではエラー時に入力値がリセットされる。
turbo_stream create のエラー表示を部分テンプレート化
エラー表示を一般化する試み。
以上です。
この記事が気に入ったらサポートをしてみませんか?