使用Rails5构建简单的IM

Rials5带来了很多新的功能,能让我们更加容易地书写web app, json API的接口,但最激动人心的应该是actioncable,长链接websocket变得如此简单,来我们用30分钟来写一个简单的即时通讯的web app,前端用JS,服务端用Ruby。actioncable的外链:(https://github.com/rails/rails/tree/master/actioncable

这个应用的功能是这样的,打开网页,注册,或者已注册用户登录,新建聊天室,或进入已有的聊天室,同一个聊天室容纳多个人,一个聊天室内所有人会收到新的聊天信息的推送。

1. 建立应用,User建模,数据迁移

环境:Ruby Version: 2.3.3,Rails Version: 5.0.2

打开ternimal, cd到相关目录下,建立工程

先不写测试了,所以没有加入自带的测试框架

打开Gemfile

这个Device是用户认证用的,简化注册登录流程,外链:https://github.com/plataformatec/devise

bootstrap主要是样式,scss,面向对象的css,可以嵌套使用,而且默认提供了一部分组件样式。redis内存是数据库,应为instance message需要及时响应,mac上brew install redis,完成以后

增加scss样式表,同时删除原来的css

写入@import “bootstrap”;

User建模

增加约束,进入网站其他页面,必须是认证用户

写入

2. 聊天室

检查chat_room.rb,确认看到belongs_to :user
检查users.rb,确认看到has_many :chat_rooms, dependent: :destroy

聊天室需要一个标题,在用户登录以后,选择聊天室时可见,而且聊天室是由用户创建的,所以和创建他的用户绑定,如果创建他的用户被删除了,那么聊天室的内容也会被删除,类似于SQL中的DELETE CASCADE效果,完了记得映射model到数据库migrate操作。

为chatroom创建controller,

写入

注意Message这个类现在还没有创建。index,展现所有chatrooms,这回事一个list,在首页,用户登录以后会看到。new是chatroom的新建操作。create是登录用户可以新建一个聊天室,聊天室创建以后会和当前用户关联。chat_room_params中的permit是参数限制,防止sql注入攻击。

建立简单的view,显示所有聊天室的view,views/chat_rooms/index.html.erb

views/chat_rooms/_chat_room.html.erb,进入聊天室的,点击按钮,以及事件

views/chat_rooms/new.html.erb,用户新建聊天室,看到那些参数,就是controller中会用到的

接下去建立message模块

检查models/chat_room.rb,看到has_many :messages, dependent: :destroy
检查models/users.rb,看到has_many :messages, dependent: :destroy
检查models/message.rb,看到belongs_to :user,belongs_to :chat_room

1:n的关系,在Rails中是1的model对应has_many,n的model对应belongs_to,一个聊天室对应多个消息,没毛病。现在chat_rooms_controller.rb中的show操作,变得有意义了,因为添加了message模块。说人话,进入对应的聊天室,展现所有的消息,不管是谁发的,对吧

views/chat_rooms/show.html.erb,聊天室详细页面,展现该聊天室的所有消息

views/messages/_message.html.erb,每一条消息的展现,默认组件card

gravatar_for头像,message.user.name用户名字,message.timestamp消息时间戳,message.body消息内容

用户注册的邮件不能直接显示在列表中,属于个人隐私,所以我们只截取@之前的那一部分作为用户的名字,models/user.rb

数据库中的时间,对用户不是很友好,我们改下显示格式,models/message.rb

记得写在gravatar_for方法,在application_helper.rb中

就是www.gravatar.com这个网站的服务,你的邮箱和你的头像绑定的第三方服务

默认的样式真的很难看,在application.scss中添加样式,@hongli,需要更加多的样式……

最后加上跳转的路由,config/routes.rb

根目录就是聊天室的列表页面

好的,模型,界面基本完成,我们要增加核心功能

3. ActionCable封装好的websocket服务,发消息,全局广播,即刻响应

看到config/cable.yml

REDISCLOUD_URL是线上环境变量

看到config/routes.rb,增加

检查javascripts/cable.js,看到

看到javascripts/application.js,增加

让cable.js的代码生效

什么是Consumer,给出外链:https://github.com/rails/rails/tree/master/actioncable#terminology
主要是解决,一个用户在多个频道,用户又有多个终端,比如不同的浏览器中同步消息

consumer可以订阅(subscribe)多个cable channels, 每个channel封装了逻辑单元,consumer闯进啊以后至少订阅一个channel。consumer订阅channel以后就成为了订阅者,一个consumer可以多次成为同一个channel的订阅者,订阅以后消息的发送和接收是双向的。你会看到其他用户发的消息,是server传输给你的,你发的消息先传给server,然后server广播给其他用户,在同一个channel上,对吧。对于websocket的链接来说,consumer是client side, channel是server side,channel类似于controller
,但是他处理的是streaming数据流,不是http的request,因为一点连接建立以后,传递的是数据流,而用http的长链接做轮训,本质上还是会close一个session的,效率很低。更加细节的内容,请自行google一下吧

我们来新建一个channel吧,javascripts/channels/rooms.coffee

CoffeeScript 是一门编译到 JavaScript 的小巧语言,外链:http://coffee-script.org/

逻辑上,如果有在页面上有,messages block,那么久client subscribe to the channel,订阅这个频道,订阅的动作依赖于room’s id,submit就是前端提交message,app会在channel内广播消息,同时输入框清空

views/chat_rooms/show.html.erb,输入消息的表单

@message应该在controller中初始化,看到chat_rooms_controller.rb中show方法中是不是创建了一个@message对象

增加message的约束,models/message.rb

讲人话,message的body属性,必须存在,2-1000个字符之间

看到views/chat_rooms/show.html.erb,@chat_room.id这个参数是subscriptions中需要的。

好了,下面看下Server的代码

channels/chat_rooms_channel.rb

感受下,是不是对应了js代码,订阅,取消订阅,发送消息,之前set的参数,在这里get。好了么?还没有,Devise的current_user,我们还没定义,channels/application_cable/connection.rb

完了以后,current_user在channel开始生效,没有认证的用户无法广播他们的消息。logger.add_tags是在console中查看debug信息。Devise 的认证是建立在Warden的基础上的,外链(https://github.com/hassox/warden),env[‘warden’].user是取得当前的login用户。

前端数据到server内存,对了还有数据库,我得把消息存起来,
models/message.rb,增加

看字面意思,广播消息以后,存到数据库

打开,jobs/message_broadcast_job.rb

perform方法做了广播的事情,得到的消息需要controller来处理,新建MessagesController,messages_controller.rb

重新看到客户端rooms.coffee,貌似已经ready了。但是你会发现,新的消息不是在最后,但我要的效果是slack那种,新的消息在底部显示,但是聊天窗口会滚动,
新增

最后,稍微美化下导航栏,不然实在太难看了。layouts/application.html.erb

现在完成了,打开rails s,打开浏览器:http://localhost:3000/,注册,以后直接就登录了,在不同浏览器,打开同一个聊天室,不同的账号登陆,试一试。
最后推送到heroku线上环境,
首先你要价格redis服务,免费的插件,https://elements.heroku.com/addons,就选Rediscloud吧,30m免费。

看到config/environments/production.rb

mark:https://radiant-fjord-14017.herokuapp.com/ 这是我的线上地址,需要替换成你自己的地址。

这是线上的demo地址:
https://radiant-fjord-14017.herokuapp.com/

所有代码的地址:
https://github.com/HongliYu/im_demo

have fun 🙂



发表评论

电子邮件地址不会被公开。 必填项已用*标注