世界上最伟大的投资就是投资自己的教育

全场限时 5 折

首页WebSocket
随风 · 练气

Websocket 学习笔记系列文章教程之 actioncable 入门 (七)

随风发布于6520 次阅读

1. 介绍

websocket 的序列文章重点要讲的就是actioncable,之前也讲了好多关于各种方式实现聊天室的文章,相信从中,也能学到好多关于 websocket 实践的知识和经验,这节要来讲讲 actioncable。

actioncable 是集成在 rails 5 中的一个功能,它能够轻易的在 rails 中使用 websocket。现在先把 actioncable 用起来,再慢慢研究其原理和特性。

2. 使用

还是跟先前的例子一样,建立一个聊天室。

2.1 聊天室界面

首先,rails 的版本必须得是 5 以上,写这篇文章的时候,rails 5 正式版还没有出来,目前的版本是 5.0.0.beta4。

$ rails new actioncable_demo
$ cd actioncable_demo

这样就生成了一个新项目。

接着创建 message 这个 model,存储聊天记录。

$ rails g model message content:text
$ rails db:migrate

创建聊天室的界面。

在 config/routes.rb 中添加路由。

Rails.application.routes.draw do
  get 'rooms/show'
end

创建 controller,添加app/controllers/rooms_controller.rb文件,内容如下:

class RoomsController < ApplicationController
  def show
    @messages = Message.all
  end
end

添加 view,添加app/views/rooms/show.html.erb文件,内容如下:

<h1>Chat room</h1>

<div id="messages">
  <%= render @messages %>
</div>

<form>
  <label>Say something:</label><br>
  <input type="text" data-behavior="room_speaker">
</form>

还有app/views/messages/_message.html.erb文件,内容如下:

<div class=“message”>
  <p><%= message.content %></p>
</div>

到目前为止,按照之前的经验,界面都建立好了,如下图所示:

2.2 开启 websocket

接下来,就是要来处理 websocket 部分。

先在客户端浏览器中开启 websocket 请求。

actioncable 默认提供了一个文件app/assets/javascripts/cable.coffee,把几行注释打开,就可以开启 websocket,内容如下:

#
#= require action_cable
#= require_self
#= require_tree ./channels
#
@App ||= {}
App.cable = ActionCable.createConsumer()

其实这些 js 的内容很简单,它做的主要的事情就是前面几篇文章所讲的在客户端浏览器执行new WebSocket,具体的内容可以查看其源码。

还要在路由中添加下面这行,把 websocket 服务以 engine 的方式挂载起来。

mount ActionCable.server : '/cable'

至此,websocket 已经开启了,可以通过 chrome 浏览器的开发者工具查看链接的信息,只要有 101 协议的信息,表示就是成功的。

2.3 channel

现在要让客户端和服务器端连接起来。

actioncable 提供了一个叫做channel的技术,中文名可以称为"通道"。actioncable 是一种pub/sub的架构,服务器通过 channel 发布消息,多个客户端通过对应的 channel 订阅消息,服务器能够广播消息给客户端,从而实现客户端和服务器端的交互。

先新建一个 channel。

$ rails g channel room speak

修改app/channels/room_channel.rb文件,内容如下:

class RoomChannel < ApplicationCable::Channel
  def subscribed
    stream_from "room_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def speak(data)
    # ActionCable.server.broadcast "room_channel", message: data['message']
    Message.create! content: data['message']
  end
end

其中定义了三个方法,分别是subscribedunsubscribedspeak

subscribedunsubscribed方法是默认就生成的,而speak是我们自己定义的。

subscribed表示的是当客户端连接上来的时候使用的方法。

unsubscribed表示的是当客户端与服务器失去连接的时候使用的方法。

还有,app/assets/javascripts/channels/room.coffee文件,内容如下:

App.room = App.cable.subscriptions.create "RoomChannel",
  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) ->
    $('#messages').append data['message']
    # Called when there's incoming data on the websocket for this channel

  speak: (message) ->
    @perform 'speak', message: message

$(document).on 'keypress', '[data-behavior~=room_speaker]', (event) ->
  if event.keyCode is 13 # return = send
    App.room.speak event.target.value
    event.target.value = ""
    event.preventDefault()

App.room里定义了四个方法,除了speakconnecteddisconnectedreceived都是 actioncable 定义的。

这几个方法可以和RoomChannel里的方法对应起来,比如:

connectedsubscribed对应,表示客户端和服务器端连接之后的情况。

disconnectedunsubscribed对应,表示客户端和服务器端失去连接之后的情况。

received表示从服务器接收到信息之后的情况。因为服务器总是要向客户端推送信息的,接收完信息之后,就可以在这里进行一些页面上的操作,比如 DOM 更新等。

room.coffee文件中有重要的一行App.room.speak event.target.value,当键入聊天信息,一按回车键后,就会通过这行代码,把聊天信息,发送到后端服务器,并且会被room_channel.rb中的speak接收,执行Message.create! content: data['message']命令。

2.4 activejob

现在还没真正完成,还差一部分。

room.coffee文件中有一个received方法,它有一行指令$('#messages').append data['message']

这个表示当聊天信息发出时,会在聊天信息展示界面上添加聊天的内容。

现在来处理这个,我们通过 activejob 来处理,还记得之前的app/views/messages/_message.html.erb文件吗,现在要发挥它的作用。

先建立一个 job。

$ rails g job message_broadcast

修改app/jobs/message_broadcast_job.rb文件,内容如下:

class MessageBroadcastJob < ApplicationJob
  queue_as :default

  def perform(message)
    ActionCable.server.broadcast 'room_channel', message: render_message(message)
  end

  private
    def render_message(message)
      ApplicationController.renderer.render(partial: 'messages/message', locals: { message: message })
    end
end

还要在一个地方执行这个 job,是当创建完 message 的时候。

修改app/models/message.rb文件,内容如下:

class Message < ApplicationRecord
  after_create_commit { MessageBroadcastJob.perform_later self }
end

做完这一切,重启一下服务器。

现在来看下效果:

本篇完结。

下一篇: websocket 之 actioncable 进阶 (八)

本站文章均为原创内容,如需转载请注明出处,谢谢。

0 条回复
暂无回复~~
相关小书
websocket教程

websocket教程

从websocket的介绍开始,从入门到精通

发表于

喜欢
统计信息
    学员: 29064
    视频数量: 1973
    文章数量: 489

© 汕尾市求知科技有限公司 | Rails365 Gitlab | Qiuzhi99 Gitlab | 知乎 | b 站 | 搜索

粤公网安备 44152102000088号粤公网安备 44152102000088号 | 粤ICP备19038915号

Top