発言をデータベースに保存する
まずは発言をデータベースに保存できるようにします。発言をDB保存するにあたり、まずはサーバー側で発言を保存した後、非同期でクライアント側にブロードキャストするよう修正します。なお、この時点では発言するのにログインは必須としていないので、ユーザーIDをchat_messagesテーブルに保存する処理は入れず、後から処理を加えます。
修正の手順をまとめると以下の通りです。
- チャネルからモデルを生成するように修正
- モデルのデータ保存をチャネル側で行うように修正
- モデルが保存されてから非同期でブロードキャストするジョブを作成
- 初期アクセス時に保存した発言が表示されるように修正
チャネルからモデルを生成するように修正
まず、チャネル内で直接ブロードキャストしていた箇所を、モデルを生成するためspeakメソッドをリスト1の通りに修正します。
class ChatMessageChannel < ApplicationCable::Channel
…(中略)…
def speak(data)
ChatMessage.create! body: data['message']
end
end
モデルの生成にはcreate!メソッドを使用します。create!メソッドは何らかの理由でレコード生成に失敗した場合に例外を投げるメソッドです。data['message']で受け取った発言をchat_messagesテーブルのbodyカラムにセットしてレコードを生成します。
モデルの修正
ブロードキャストする処理をモデルが生成した後のタイミングで行うよう、リスト2の通りに修正します。
class ChatMessage < ApplicationRecord
after_create_commit { ChatMessageBroadcastJob.perform_later self }
end
after_create_commitメソッドは、ActiveRecordのcreateまたはcreate!メソッドが呼び出されてデータベースへのコミットが正常終了した後に、{}で指定したブロックが後処理として呼び出します。ChatMessageBroadcastJobは、次の手順で作成するジョブでperform_laterメソッドを通じて呼び出すことができます。引数にself、つまりモデル自身を渡しています。
非同期でブロードキャストするジョブの作成
ジョブとは、Rails 4.2から導入された非同期処理の仕組みのことで、Active Jobと呼ばれます。ジョブファイルの生成は、Railsが提供するジェネレーターコマンドを使用します。
bin/rails g job ChatMessageBroadcast
↓
Running via Spring preloader in process 83621
invoke test_unit
create test/jobs/chat_message_broadcast_job_test.rb
create app/jobs/chat_message_broadcast_job.rb
ジェネレーターコマンドで自動生成されたファイルを確認してみましょう。
class ChatMessageBroadcastJob < ApplicationJob
queue_as :default
def perform(*args)
# Do something later
end
end
queue_asメソッドは、ジョブを実行するキューの名前を指定するものです。呼び出し側でperform_laterメソッドによってジョブが呼び出されると、performメソッドに記述された処理が実行されます。このジョブが実行されたら、ブロードキャストする処理をperformメソッドに記述しましょう。
class ChatMessageBroadcastJob < ApplicationJob
…(中略)…
def perform(chat_message)
ActionCable.server.broadcast 'chat_message_channel', message: chat_message.body
end
end
追加したブロードキャストする処理は、元々チャネルのspeakメソッドで定義していた処理のままです。
初期アクセス時に保存した発言が表示されるように修正
次に、保存した発言をデータベースから取得して表示されるように修正します。まずはコントローラーをリスト5の通りに修正しましょう。
class ChatMessagesController < ApplicationController
def index
@chat_messages = ChatMessage.all
end
end
ChatMessage.allで全ての発言をchat_messagesテーブルから取得して、インスタンス変数@chat_messagesに代入してビューで使用できるようにします。
次にビューをリスト6の通りに修正しましょう。
<div id='chat_messages'>
<% @chat_messages.each do |chat_message| %>
<div><%= chat_message.body %></div>
<% end %>
</div>
…(中略)…
全ての発言が代入されている@chat_messagesをeachでループして、1つ1つの発言をdiv要素で囲んで表示しています。
動作確認
これで、一通り発言をデータベースに格納した後にブロードキャストする修正が完了しました。「http://localhost:3000/chat_messages/index」にアクセスして動作確認をしてみましょう。
