本文概述
Volt是一个为数据丰富的应用程序设计的Ruby框架。服务器端和客户端都使用Ruby编写(然后使用OPAL编译为JS), 因此这使开发人员可以编写非常动态的应用程序, 而不必编写一行Javascript代码。如果你是像我这样的Ruby粉丝, 那么你会喜欢这个框架的。
为了使Web应用程序更具动态性, 前端Javascript框架(例如Angular.js, Backbone.js和Ember.js)获得了很大的普及。但是, 这些框架通常需要后端应用程序才能有用, 因此它们与Ruby on Rails和Django等Web框架结合使用。
另一方面, Ruby框架Volt能够管理后端和动态前端。由于这两种功能都紧密集成到其核心中(实际上, Volt更像是MVVM体系结构, 利用了数据绑定的优势), 因此它使开发人员能够快速构建这些应用程序。
开箱即用的一项非常酷的功能是Volt的实时功能。如果你曾经制作过实时应用程序, 那么你就会知道该过程可能会很困难–你可能实施了AJAX轮询, Web套接字, 服务器发送事件(SSE)甚至使用了外部服务, 这增加了应用程序的复杂性, 甚至产生了额外的成本。与其他框架不同, Volt(通过Web套接字)保持与服务器的连接保持活动状态, 因此, 它无需为每个操作发出Ajax请求, 而是立即将更改推送给所有客户端。无需配置即可工作。
使用伏特创建聊天应用程序
在本Ruby框架教程中, 我将带你完成使用Volt创建实时应用程序的过程, 以及比聊天应用程序更好的方法来展示其功能, 因为聊天仍然是实时应用程序的第一个用例。
首先, 让我们安装Volt和MongoDB。后面的过程将不再详细介绍:
gem install volt
brew install mongodb
mkdir -p /data/db
(创建dbpath)
chown `id -u` /data/db (change the owner to have the proper dbpath permissions)
现在, 我们准备创建我们的第一个应用程序, 称之为”聊天”。我们可以通过以下几行轻松地做到这一点:
volt new chat
cd chat
文档结构与Rails有一些相似之处。 Rails用户会注意到的主要区别是, 应用程序内部有一个额外的文件夹, 其中包含资产, 控制器, 模型和视图等其余文件夹, 此额外文件夹是”组件”。
组件是应用程序的隔离部分。组件内的所有页面都呈现出来而无需重新加载页面, 因为该组件的所有文件都已加载了初始的http请求, 因此, 如果我们访问其他组件的页面, 则会发出新的http请求, 并且页面将被”重新加载” ‘。在此示例中, 我们使用默认组件” main”。
让我们通过在控制台中执行” volt server”命令来启动服务器, 并通过导航至localhost:3000来查看其在浏览器中的外观:
volt server
另外, 不要忘记在控制台中启动MongoDB:
mongod
我们可以注意到, Volt带有许多默认页面, 包括”首页”和”关于”。这些可以立即进行定制。
另一点值得一提的是页面右上方的登录按钮。 Volt通过” volt-user-templates” gem将”用户”功能集成到框架中, 该功能提供了一种开箱即用的方式来注册和验证用户。
入门
现在, 让我们开始开发我们的应用程序。首先, 我们不需要”关于”页面, 因此我们可以继续删除以下内容:app / main / views / main / about.html文件, app / main / controllers / main_controller.rb中的about操作, 请在app / main / config / routes.rb中删除/ about路由, 并在app / main / views / main / main.html中删除导航链接。
<ul class="nav nav-pills pull-right">
<:nav href="/" text="Home" />
<:user-templates:menu />
</ul>
现在开始做生意, 首先列出所有注册用户:
<:Body>
<h1>Home</h1>
<div class="row">
<div class="col-md-4">
{{ _users.each do |user| }}
<div class="contact">
{{user._name}}
</div>
{{ end }}
</div>
</div>
现在, 所有注册用户都在主页中列出。请注意, {{}}中编写的代码是要执行的Ruby代码。这样, 我们可以遍历用户集合并打印出每个用户集合。
你可能已经注意到, “用户”是存储所有用户的集合的名称;要记住的一点是, 访问属性时要在属性名称前加上下划线””。为此, 我们首先需要在main_controller.rb文件顶部添加一行代码:
model :store
Volt带有可从控制器访问的多个收集模型, 并且每个模型都将信息存储在不同的位置。商店收集模型将数据存储在数据存储中, 在这里我们指定使用该控制器的控制器(目前唯一支持的数据存储是MongoDB)。让我们创建几个用户来查看外观。
目前, 此页面没有什么令人兴奋的, 我们只是列出注册用户。现在, 我希望能够选择要向其发送消息的用户, 从列表中删除当前登录用户的名称(因为他不应该向自己发送消息), 仅将列表显示给已认证的用户用户, 并向未经身份验证的用户显示”着陆”页面:
<:Body>
<h1>Home</h1>
{{ if Volt.user }}
<div class="row">
<div class="col-md-4">
{{ _users.each do |user| }}
{{ if user._id != Volt.user._id }}
<div class="contact {{ if params._user_id == user._id }} active {{ end }}" e-click="select_conversation(user)">
{{user._name}}
</div>
{{ end }}
{{ end }}
</div>
</div>
{{ else }}
<p>This is a sample application built with Volt to demonstrate its real-time capabilities. Please log in to access it.</p>
{{ end }}
Volt.user返回当前(已登录)用户或nil。
通过e-click属性, 我们可以从控制器中选择一个方法, 该方法将在单击该元素时被调用。
属性和CSS
实际上, 所有” e”属性在Volt中都是事件绑定器, 因此, 例如, 我们可以将e-submit添加到表单中以选择将在控制器上调用的操作。我们将在参数中添加”选定的”用户ID, 以便我们知道已选择了哪个ID, 并添加了一个名为”活动”的类, 以后可以对其进行样式设置。
现在, 让我们在控制器中创建select_conversation方法:
def select_conversation(user)
params._user_id = user._id
end
就是这样–如果你再次签出该页面, 则可以看到每次单击用户名时URL都会更改。另外, ” active”类已添加到该元素, 因此让我们添加一些CSS以使其可见(我将继续为以后添加的项目添加CSS):
.conversation{
form{
input{
margin: 10px 0 5px 0;
}
}
}
.contact{
width:100%;
padding:5px;
margin: 4px 0;
font-size:15px;
cursor:pointer;
&:hover{
background-color: #FAFAFA;
}
&.active{
background-color: #337ab7;
color: #FFF;
}
.badge{
background-color: #900;
}
}
.message{
max-width: 80%;
padding:10px 15px;
margin: 5px 0;
background-color: #FEFEFE;
border: 1px solid #E7E7E7;
border-radius: 5px;
float: left;
clear:both;
&.sent{
background-color: #E4F3DB;
border: 1px solid #B7D0A7;
float: right;
}
p{
margin:0;
}
}
现在, 让我们在右侧创建一个表单, 向每个用户发送消息:
<:Body>
<h1>Home</h1>
{{ if Volt.user }}
<div class="row">
<div class="col-md-4">
{{ _users.each do |user| }}
{{ if user._id != Volt.user._id }}
<div class="contact {{ if params._user_id == user._id }} active {{ end }}" e-click="select_conversation(user)">
{{user._name}}
</div>
{{ end }}
{{ end }}
</div>
{{ if params._user_id }}
<div class="col-md-8 well conversation">
{{ current_conversation.each do |message| }}
<div class="message {{ if message._sender_id == Volt.user._id }} sent {{ end }}">
<p>{{ message._text }}</p>
</div>
{{ end }}
{{ if current_conversation.count == 0 }}
<p>You have no messages yet. Start chatting!</p>
{{ else }}
<div class="clearfix"></div>
{{ end }}
<form e-submit="send_message" role="form">
<div class="form-group">
<input class="form-control" type="text" placeholder="Write a message" value="{{ page._new_message }}" />
<button type="submit" class="btn btn-primary pull-right">Submit</button>
</div>
</form>
</div>
{{ end }}
</div>
{{ else }}
<p>This is a sample application built with Volt to demonstrate its real-time capabilities. Please log in to access it.</p>
{{ end }}
首先, 我们在显示表单之前先检查是否有选中的用户, 然后我们将通过稍后将要定义的控制器中的方法显示当前对话(与所选用户的对话)中的所有消息, 在底部, 我们正在显示用于发送新消息的表单。
请注意, 输入值是我们在页面集合模型上创建的属性, 因为我们不希望将其存储在数据存储区中。现在, 让我们在控制器中定义current_conversation和send_message方法:
def send_message
unless page._new_message.strip.empty?
_messages << { sender_id: Volt.user._id, receiver_id: params._user_id, text: page._new_message }
page._new_message = ''
end
end
def current_conversation
_messages.find({ "$or" => [{ sender_id: Volt.user._id, receiver_id: params._user_id }, { sender_id: params._user_id, receiver_id: Volt.user._id }] })
end
在send_message方法中, 如果消息不为空(我们正在检查内联, 因此我们现在不必打扰验证), 则向集合中添加新消息, 然后将页面._new_message设置为”, 我们清空输入字段。
我们可能还希望将该行添加到select_conversation方法的末尾。当前的对话方法仅查询_messages集合以获取所选用户和当前用户之间的消息。
总结实时通知
最后, 我想拥有某种通知系统, 以便用户可以看到其他用户何时向他们发送消息。
让我们添加一个名为_notifications的新集合, 并在每条消息发送后创建一个新集合:
def send_message
unless page._new_message.strip.empty?
_messages << { sender_id: Volt.user._id, receiver_id: params._user_id, text: page._new_message }
_notifications << { sender_id: Volt.user._id, receiver_id: params._user_id }
page._new_message = ''
end
end
def select_conversation(user)
params._user_id = user._id
unread_notifications_from(user).then do |results|
results.each do |notification|
_notifications.delete(notification)
end
end
page._new_message = ''
end
def unread_notifications_from(user)
_notifications.find({ sender_id: user._id, receiver_id: Volt.user._id })
end
另外, 我们需要在用户选择对话并查看新消息后删除通知, 因此我将该部分添加到select_conversation方法中。
让我们在用户名旁边添加一个通知计数器:
<div class="contact {{ if params._user_id == user._id }} active {{ end }}" e-click="select_conversation(user)">
{{user._name}}
{{ if unread_notifications_from(user).count > 0 }}
<span class="badge">
{{ unread_notifications_from(user).count }}
</span>
{{ end }}
</div>
现在该应用程序已准备就绪, 你可以打开几个浏览器并开始测试Volt的实时功能。
伏特绝对值得一试
尽管Volt框架不像已经流行了很多年的大多数流行的Ruby框架(目前Volt仍处于beta版)那样成熟和健壮, 但还是值得考虑和研究的。
如果你有兴趣, 请使用此Ruby框架教程将Volt试一下。密切关注进一步的开发, 因为即使在开发的初期, Volt仍然看起来是非常有前途的Ruby框架。
管道中有许多很酷的新功能, 我敢肯定, 随着越来越多的人开始尝试Volt, Volt在接下来的几年中将变得越来越重要。由于具有许多创新功能, 许多开发人员可能会爱上Volt并将其用于下一个Ruby项目。
评论前必须登录!
注册