#はじめに
Railsを使って簡単なチャットアプリを作ったので、そのときの手順をまとめました。
#環境
$ ruby -v
ruby 2.5.1p57 (2018-03-29 version 63029) [x86_64-darwin19]
$ bin/rails -v
Rails 5.2.3
#参考
チャットアプリを作る際、以下を参考にさせて頂きました。
この記事で掲載しているソースコードの大半は下記の2つのページの内容が基になっています。
Action Cableでリアルタイムチャットアプリの作成方法 (Rails 5.1.4にて)(その1) herokuで動かす!
Rails 5 + ActionCableで作る!シンプルなチャットアプリ(DHH氏のデモ動画より)
#ソースコード
チャットアプリのソースコードは以下で確認できます。
Neufo/rails-sample-app/ChatApp
#手順
1. アプリケーションを作る
まずはチャット機能を実装するアプリケーションを作ります。
$ rails new ChatApp
2. コントローラーを作る
ChatAppディレクトリに移動して以下のコマンドを実行します。
$ bin/rails generate controller rooms show
これでChatApp/app/controllers/
にrooms_controller.rb
が作られます。
3. モデルを作る
ユーザーが入力したメッセージを保存するモデルを作ります。
$ bin/rails generate model message content:text
$ bin/rails db:migrate
4. メッセージの一覧を表示する
RoomsControllerのshowメソッドでメッセージの一覧を取得します。
class RoomsController < ApplicationController
def show
@messages = Message.all
end
end
取得したメッセージを表示するためにViewを編集します。1
<h1>Chat room</h1>
<div id="messages">
<%= render @messages %>
</div>
messagesの各要素をページに埋め込むために部分テンプレートを作ります。
(ChatApp/app/views/ に messagesフォルダを作り、その中にファイルを保存します)
<div class="message">
<p><%= message.content %></p>
</div>
5. チャンネルを作る
クライアント/サーバ間の通信処理のひな形を作ります。
$ bin/rails generate channel room speak
コマンドを実行するとクライアント用、サーバ用のファイルが作られます。
- ChatApp/app/assets/javascripts/channels/room.coffee (クライアント)
- ChatApp/app/channels/room_channel.rb (サーバ)
サーバを起動して動作を確認してみます。
$ bin/rails s
ブラウザで/rooms/show
を開き、コンソールでApp.room.speak()
と入力します。trueが返ってくれば成功です。
6. jQueryを有効にする
クライアントがメッセージを送受信するときにjQueryを使うので準備しておきます。
gem 'jquery-rails'
上記をGemfileに追記したらbundle update
を実行します。
jQueryのライブラリを読み込むようapplication.jsに追記します。
(省略)
//= require jquery
//= require jquery_ujs
//= require_tree .
7. メッセージの送受信処理を作る
以下の機能を作ります。
- クライアント側
- サーバからメッセージを受信する (received)
- ユーザが入力したメッセージをサーバに送信する (speak)
<form>
<label>Say something:</label><br>
<!-- room_speaker からサーバへメッセージを送信する -->
<input type="text" data-behavior="room_speaker">
</form>
$(document).on 'keypress', '[data-behavior~=room_speaker]', (event) ->
# Enterキーが押されたらサーバへメッセージを送信する
if event.keyCode is 13 # return = send
App.room.speak event.target.value
event.target.value = ''
event.preventDefault()
App.room = App.cable.subscriptions.create "RoomChannel",
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
# メッセージ一覧の末尾に受信したメッセージを追加する
$('#messages').append data['message']
speak: (message) ->
# サーバのspeakメソッドを呼び出す
@perform 'speak', message: message
- サーバ側
- room_channelを購読する (subscribed)
- クライアントから受信したメッセージを保存する (speak)
- room_channelに参加しているクライアントにメッセージをブロードキャストする (perform)
class RoomChannel < ApplicationCable::Channel
def subscribed
# room_channelからデータを受信する
stream_from "room_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
def speak(data)
# データベースにクライアントから受信したメッセージを保存する
Message.create! content: data['message']
end
end
メッセージをブロードキャストするジョブを定義します。
$ rails generate job MessageBroadcast
class MessageBroadcastJob < ApplicationJob
queue_as :default
def perform(message)
# room_channelにメッセージをブロードキャストする
ActionCable.server.broadcast 'room_channel', message: render_message(message)
end
private
def render_message(message)
ApplicationController.renderer.render(partial: 'messages/message', locals: { message: message })
end
end
データベースにメッセージを保存したら、ジョブを登録します。
class Message < ApplicationRecord
# データベースにメッセージが保存されたらジョブを登録する
after_create_commit { MessageBroadcastJob.perform_later self }
end
登録されたジョブは自動的に実行されます。
MessageBroadcastJobのperformメソッドが呼び出され、すべてのクライアントにメッセージが送信されます。
クライアントはreceivedでメッセージを受け取り、メッセージ一覧の末尾に受信したメッセージを追加します。
これでチャットアプリの作成は終了です。
-
<%= render @messages %>
は<%= render partial: "messages/message", collection: @messages %>
を省略形です。参考:コレクションをレンダリングする ↩