発言をデータベースに保存する
まずは発言をデータベースに保存できるようにします。発言を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
」にアクセスして動作確認をしてみましょう。