Action Cableの習作: stream_fromとbroadcast_to

外観

Action Cableのstream_fromとbroadcast_toを使ってメッセージをやり取りしてみます。

画像1

環境

macOS 10.15.4
Ruby 2.7.0
Rails 6.0.3
Yarn 1.22.4
Node 13.12.0
stimulus@1.1.1

リポジトリ

参照

stream_from(broadcasting, callback = nil, coder: nil, &block)
Start streaming from the named broadcasting pubsub queue.

broadcast_to(model, message)
Broadcast a hash to a unique broadcasting for this model in this channel.

rails/actioncable/lib/action_cable/channel/broadcasting.rb

疎通確認

準備
rails new try_ac_simple_broadcast
cd try_ac_simple_broadcast
bin/rails g controller Messages index
config/routes.rb
root 'messages#index'

ChatChannel
'chat:message'でやりとりします。

bin/rails g channel chat

app/channels/chat_channel.rb

 def subscribed
   stream_from 'chat:message'
 end

 def post(data)
   ChatChannel.broadcast_to('message', data['message'])
 end

app/javascript/channels/chat_channel.js

 post(message) {
   this.perform('post', { message: message })
 },

 received(data) {
   console.log(data)
 },

一旦、参照しやすいようにしておきます。

window.chat = consumer.subscriptions.create("ChatChannel", {

ウェブブラウザのコンソールで確認してみます。
chat.post('Hello')

画像2

Railsサーバの出力:
ChatChannel#post({"message"=>"Hello"})
[ActionCable] Broadcasting to chat:message: "Hello"
ChatChannel transmitting "Hello" (via streamed from chat:message)

画面表示

bin/rails webpacker:install:stimulus

app/views/messages/index.html.erb

...
<% form_data = {} %>
<% form_data['controller'] = 'chat' %>
<% form_data['action'] = 'ajax:beforeSend->chat#post' %>
<% text_field_data = { target: 'chat.message' } %>

<%= form_with url: '#', id: 'message', data: form_data  do %>
 <%= text_field_tag 'body', '', data: text_field_data %>
<% end %>

<ul id="messages"></ul>

app/javascript/controllers/chat_controller.js
chat_channel.jsの内容を持ってきます。

import { Controller } from "stimulus"
import consumer from "channels/consumer"
export default class extends Controller {
  static targets = [ "message" ]
 connect() {
   this.chat = consumer.subscriptions.create("ChatChannel", {

     received(data) {
       const li = document.createElement('li')
       li.textContent = data
       document.getElementById('messages').appendChild(li)
     },

     post(message) {
       this.perform('post', { message: message })
     }
   });
 }
 post(event) {
   event.preventDefault()
   if (this.chat.consumer.connection.isOpen()) {
     this.chat.post(this.messageTarget.value)
     this.messageTarget.value = ''
   }
 }

rm app/javascript/channels/chat_channel.js

以上です。


この記事が気に入ったらサポートをしてみませんか?