何かやってみるブログ

興味をもったこと、趣味のこと、技術について色々書きます。

[Rails] いまさらActionCableを試してみる

Railsを1年くらい触っているのに、ActionCableを触ったことがなかったので、適当な掲示板的なアプリを作りながらActionCableに触ってみました.

Action Cableとは

RailsにWebSocketの仕組みを簡単に導入できるようにしてくれるフレームワーク

railsguides.jp

WebSocketとは

双方向のプロトコルでリアルタイムの通信が可能で、Ajaxの代わりになるかと言われている技術

ja.wikipedia.org

環境構築

rubyは2.6.5、Railsは6.0.3.1、PostgresSQLは12.3を使って作ります.

➜  ~ rails -v
Rails 6.0.3.1
➜  ~ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin19]
➜  ~ psql --version
psql (PostgreSQL) 12.3
$ rails new chat_app_sample -d postgresql
$ rails db:create 
$ rails s

http://localhost:3000 にアクセスしてYay! You’re on Rails!が表示されることを確認出来ました.

f:id:s-takaya1027:20200530202531p:plain

Action Cableを使わずにメッセージの作成機能と一覧表示機能を実装する

Message modelを作成します.

$ rails g model Message body:string
$ rails db:migrate

messages controllerを作成します

$ rails g controller messages index create

routingを整理します.

Rails.application.routes.draw do
  root to: "messages#index"
  resources :messages, only: [:create, :index]
end

messages controllerを実装していきます.

class MessagesController < ApplicationController
  def index
    @message = Message.new
    @messages = Message.all
  end

def create @message = Message.new(message_params) if @message.save redirect_to messages_path end end

private

def message_params params.require(:message).permit(:body) end end

Viewを編集していきます.

<h1>Messages#index</h1>
<ul id="messages_list">
  <%= render @messages %>
</ul>

<%= form_with(model: @message, local: true) do |f| %> <%= f.label :body, "内容" %> <%= f.text_field :body %> <%= f.submit %> <% end %> </div>

<li><%= message.body %></li>

以上の実装でメッセージの作成の成功時、リダイレクトされて画面が更新されてメッセージ一覧が表示されるところまで実装できました.

Action Cableを導入してみる

Channelを作成し、cableをmountさせます.

$ rails g channel message

Rails.application.routes.draw do
  root to: "messages#index"
  resources :messages, only: [:create, :index]
  mount ActionCable.server, at: '/cable'  #追加
end

subscribedメソッドでmessage_channelをストリーミングさせます.

class MessageChannel < ApplicationCable::Channel
  def subscribed
    stream_from "message_channel"
  end

def unsubscribed # Any cleanup needed when channel is unsubscribed end end

ログでchannelをストリームされていることが確認できました.

f:id:s-takaya1027:20200530223000p:plain

ストリームされていることを確認できたので、Messageが作成されたらブロードキャストされるようにmessages#createを修正します.

・
・
  def create
    message = Message.new(message_params)
    if message.save
      ActionCable.server.broadcast "message_channel", message: message.body
    end
  end

app/javascript/channels/message_channel.jsでブロードキャストされた時の処理を書きます.

import consumer from "./consumer";

consumer.subscriptions.create("MessageChannel", { 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) {
// データを操作する const list = document.createElement('li'); list.textContent = data.message; const lists = document.getElementById('messages_list'); lists.append(list); //残ったテキストフィールドを空にする document.getElementById('message_body').value = ''; }, });

動作確認

リアルタイムで動くことが確認できました.😀

youtu.be