---
# System prepended metadata

title: 12th 鐵人賽 Day_26 action cable ?(3)
tags: [12th 鐵人賽]

---

---
title: 12th 鐵人賽 Day_26 action cable ?(3) 
tags: 12th 鐵人賽
--- 
# 12th 鐵人賽 Day_26 action cable ?(3) 

嗨！各位朋友大家好，烤肉節快樂，我是阿圓，一樣有請今天的one piece：
![](https://i.imgur.com/mzwoFQx.png)
(烤肉慶典持續中！)

昨天我們說完了 Pub/Sub 模式，今天來說說 Rails 中的 action cable。

# action cable 基本介紹
再來複習一下昨天的圖：
![](https://miro.medium.com/max/450/1*-GHFC93E4ODwNc98IE5_vA.png)
>publisher 發送出去的訊息，透過代理層(message broker)的方式將訊息廣播給 subscriber

而 Rails 中，代理層的部分是 channel，可以透過產生器，來產生channel
`rails g channel xxx` 
xxx 可以換成想取的名字 ~~(例如，親親小可愛之類的)~~，會建立出下面這些檔案：
```bash=
Running via Spring preloader in process 27571
      invoke  test_unit
      create  test/channels/xxx_channel_test.rb
      create  app/channels/xxx_channel.rb
   identical  app/javascript/channels/index.js
   identical  app/javascript/channels/consumer.js
      create  app/javascript/channels/xxx_channel.js
```
先來看 `app/channels/xxx_channel.rb`，這裡面是定義當 subscriber，訂閱，或是取消訂閱 channel時的事情。
```ruby=
class XxxChannel < ApplicationCable::Channel
# 會有一個最上層的 channel，底下有很多的小 channel。
  def subscribed
    stream_from "qqq_stream"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
end
```
channel 透過 stream 來廣播訊息，常用的有以下方法：
`stop_all_streams()` ：取消所有stream。
`stream_from "xxx_channel"` ：透過名為xxx_channel的stream 來廣播。
`stream_for (model)` ：可以透過以建立的 model，來產生stream 廣播。

---

而`app/javascript/channels/xxx_channel.js`，則是定義了 client 端的行為，分別有：
```javascript=
import consumer from "./consumer"
consumer.subscriptions.create("XxxChannel", {
  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) {
    // 接收資料
    // Called when there's incoming data on the websocket for this channel
  }
});
```
其中 `consumer.subscriptions.create("XxxChannel",{...})`，這裡的意思是將 consumer 連上 XxxChannel，當 channel 那邊透過 stream(上面定義的名稱是'qqq_stream') 廣播出訊息，就會藉由 received 的 function 接收到資料。

這樣已經將簡單的連線做好了，但若要實際看到效果，還需要做一點設置：
```yaml=
# /cable.yml
development:
  adapter: async
  #把這邊改成 redis

test:
  adapter: test

production:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
  channel_prefix: Test_production
```
(redis 是一種無關聯性、 key-value 型的資料庫，一般會搭配關聯性資料庫，作為快取用，其他詳細介紹，請參考 [wiki](https://en.wikipedia.org/wiki/Redis))


最後就可以去 rails console 裡面：
```bash=
ActionCable.server.broadcast "qqq_channel", {message:"Hello world!"}
# 請記得，channel 是透過 stream 來廣播訊息！
```

這樣身為`XxxChannel`中`qqq_stream`的訂閱者，都可以收到這條訊息，並且在瀏覽器的 console 裡顯示出來。
![](https://i.imgur.com/2aTpxgg.png)
(若廣播成功會回傳1)

以上就是今天的 action cable 基本介紹，明天我們再來進階一些，感謝各位看到這邊，若有任何建議，請各位不吝指教！我們明天見！
![](https://i.imgur.com/PPbpd2b.gif)

---

#### 參考文章
[官方文件](https://guides.rubyonrails.org/action_cable_overview.html)
[官方手冊](https://api.rubyonrails.org/classes/ActionCable/Channel/Streams.html)
