使用 ActionCable 实时更新 Rails App Wall Feed
介绍
Rails 6 包含许多现成的功能,可通过 ActionCable 库轻松为您的 Web 应用创建发布/订阅(简称 pub/sub)功能。如今,这种要求对于现代 Web 应用来说很常见。例如,假设您想要实现类似于 Facebook 的墙式信息流,其中当系统中创建新帖子时,这些帖子将出现在信息流中,而无需刷新页面。在本指南中,您将了解如何使用 ActionCable 创建发布/订阅机制,以在墙式信息流中呈现新帖子。
基本概念
让我们首先建立发布/订阅系统的基本概念,以便理解 ActionCable 的不同组件。
渠道
频道是客户端程序可以连接以开始接收消息的任何流或位置。在本指南中,您将创建一个wall_channel。广播到此频道的消息将是系统中保存的新帖子。
广播员
广播器是可以向频道发送消息的任何组件。Rails 中的消息以编程方式表示为哈希对象。
订户
客户端以订阅者的身份连接到频道。连接后,如果广播者通过频道发送消息,订阅者将能够看到该消息。在实现方面,使用加载在页面中的javascript代码订阅频道并提供处理收到的消息的回调函数。
设置
首先创建一个新的 Rails 6 项目。您可以随意命名,但出于本指南的目的,该项目将命名为acdemo:
$ rails new acdemo
ActionCable 配置文件
您应该在config/cable.yml上找到ActionCable的配置文件。如果您在开发环境中工作,则使用的默认适配器称为async。适配器是 ActionCable 使用的排队机制,用于存储要广播到不同频道的消息。async告诉框架使用内存数据存储,这在某些环境中可能不会立即起作用。建议使用本地运行的 Redis 服务器来处理排队。
这是cable.yml中用于开发的默认配置:
development:
adapter: async
将其更改为以下内容以告诉 ActionCable 使用 Redis:
development:
adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
Redis 服务器
如果你尚未运行 Redis 服务器,请根据你选择的平台进行安装:
Mac OS X
确保您已经安装了brew。
$ brew update
$ brew install redis
$ brew services start redis
Ubuntu
$ sudo apt install redis-server
$ sudo service redis-server restart
视窗
不幸的是,Redis 不适用于 Windows。不过,你可以通过 WSL2 在 Windows 中安装 Ubuntu。安装说明可在此处找到。
创建频道
要创建名为wall_channel的通道,请发出以下命令:
$ rails g channel wall
该命令将生成以下重要文件:
- app/channels/wall_channel.rb:代表频道的后端组件。现在,确保在订阅方法中调用stream_from “wall_channel”方法。
- app/javascript/channels/wall_channel.js:客户端代码包含订阅频道时的不同事件处理程序方法。
惯例是,先前发出的命令中的通道名称是wall,它在 Rails 后端转换为wall_channel ,但在客户端代码上称为WallChannel 。
您的app/channels/wall_channel.rb代码应如下所示:
class WallChannel < ApplicationCable::Channel
def subscribed
stream_from "wall_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
在文件app/javascript/channels/wall_channel.js中,您将找到三个函数。当您的客户端代码订阅 WallChannel 时,将触发connect ()函数。现在,您可以通过登录到控制台来验证它确实订阅了该频道。
connected() {
console.log("Connected to WallChannel");
}
您现在可以暂时保留第二个函数disconnected(),但基本上这就是在终止频道订阅后放置额外客户端代码的地方。
第三个函数received(data)是客户端代码处理广播到频道的传入数据的地方,这些数据由 data参数表示。在本例中,data表示您可以附加到页面界面的新创建的帖子。输入以下代码,它将创建表示帖子的 HTML 元素并将其附加到id 为wall的<div>中。
received(data) {
wall = document.getElementById('wall');
wall.innerHTML +=
"<h2>" + data.title "</h2>";
wall.innerHTML +=
"<p>" + data.content + "</p>";
}
您的app/javascript/channels/wall_channel.js应如下所示:
import consumer from "./consumer"
consumer.subscriptions.create("WallChannel", {
connected() {
// Called when the subscription is ready for use on the server
console.log("Connected to WallChannel");
},
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
wall = document.getElementById('wall');
wall.innerHTML +=
"<h2>" + data.title "</h2>";
wall.innerHTML +=
"<p>" + data.content + "</p>";
}
});
创建根页面
创建一个默认根页面,该页面将在从 WallChannel 接收到创建的帖子时“流式传输”这些帖子。
在文件config/routes.rb中,输入以下行:
root to: "pages#index"
使用以下代码创建文件app/views/pages/index.html.erb :
<h1>Wall Posts</h1>
<div id="wall">
</div>
默认情况下,Rails 6 已加载由application.js在require('channels')行中调用的所有 JavaScript 通道代码。因此,您的app/javascript/channels/wall_channel.js将在应用程序的所有页面中加载。您可以通过启动 Rails 服务器并刷新根页面来测试这一点。您应该注意到控制台中打印了上一步中编程的Connected to WallChannel。这表明客户端代码(订阅者)现在已连接到WallChannel。
创建模型
创建一个名为Post的模型,其属性title和content均为字符串类型。
$ rails g model Post title:string content:string
$ rails db:migrate
<
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~