rails4 actioncable

15年的时候,出了rails5,有个新特性actioncable.刚好公司有个关于推送的需求,但是Rails的版本是Rails4.想使用actioncable. 找了很久找到了一个可以使用的官方的gem. 16年的时候在公司项目中用了进去.
现在打算把这个写出来,因为好像很多人都不知道rails4有这个gem可以使用.

actioncable

gemfile添加

1
gem 'actioncable', github: 'rails/actioncable', branch: 'archive'

ps: 为了防止作者把分支删除,可以先备份一个到自己的仓库里.

bundle之后需要配置一番,这个可不像rails5那么棒,不用配置都行.
application.js

1
2
3
...
//= require cable
...

app 文件夹下创建相关的目录
channels/application_cable/channel.rb

1
2
3
4
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end

channels/application_cable/connection.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :push_store
def connect
self.push_store = find_verified_user.store
end
protected
def find_verified_user
session_key = Rails.application.config.session_options[:key]
user_id = cookies.encrypted[session_key]['user_id']
if verified_user = User.find_by(id: user_id)
verified_user
else
reject_unauthorized_connection
end
end
end
end
# note: 因为websocket不支持session传输,所以此处需要由cookies解密

channels/orders_channel.rb

1
2
3
4
5
6
7
8
9
10
class OrdersChannel < ApplicationCable::Channel
def subscribed
stream_from "order_channel_#{push_store.id}"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
# subscribed是连接过来发生的行为,unsubscribed是断开连接发生的行为。

我们在上面将最基本的桥梁搭建好了,那么我得去创建一个消费者去使用他。 在 app/javascripts/下创建一个 app.es6

1
2
3
4
5
6
7
8
9
let App = {};
App.cable = Cable.createConsumer(`/cable`);
App.messaging = App.cable.subscriptions.create('OrdersChannel', {
received: function(data) {
$(this).trigger('received', data);
}
});

消费者创建好之后,我们需要播报一条消息,让他去监听行为并做出处理 在 app/jobs下创建 order_broadcast_job.rb

1
2
3
4
5
6
7
class OrderBroadcastJob < ActiveJob::Base
queue_as :default
def perform(store)
ActionCable.server.broadcast "order_channel_#{store.id}", { message: "message", user: "current_user" }
end
end

可以发现,这个任务就是去向order_channel播报一条通知,可以理解为:‘我发布了一个广播,指定进入到order_channel. 连接上来,自然而然的触发了subscribed。广播指定的通道,会去匹配stream_from.

上面我们发布了一个广告有任务了,那么消费者就会积极相应,主动接收任务。 接收了任务之后,就会发生对应的行为。app/javascripts/order.es6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$(function($) {
$(App.messaging).on('received', function(event, data) {
let count = 0
const message = () => {
count++;
if(count%2==1){
document.title='【你有新的消息】'
}else {
document.title='【      】'
}
}
setInterval(message, 800)
});
});

新建cable文件夹,与app文件夹同级 cable/config.ru

1
2
3
4
5
6
require ::File.expand_path('../../config/environment', __FILE__)
Rails.application.eager_load!
require 'action_cable/process/logging'
run ActionCable.server

bin文件夹下创建cable脚本

1
2
#!/bin/bash
bundle exec puma -p 28080 cable/config.ru

本地使用的时候,直接 $bin/cable就好.

关于部署可以参考我的笔记.actioncable发布

原文