Action Cableの習作: stream_fromとbroadcast_to
外観
Action Cableのstream_fromとbroadcast_toを使ってメッセージをやり取りしてみます。
環境
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')
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
以上です。