认识 Volt,一个用于动态应用程序的有前途的 Ruby 框架

已发表: 2022-03-11

Volt 是一个为数据丰富的应用程序设计的 Ruby 框架。 服务器端和客户端都是用 Ruby 编写的(然后使用 OPAL 将其编译为 JS),因此这允许开发人员编写非常动态的应用程序,而无需编写一行 Javascript 代码。 如果你和我一样是 Ruby 爱好者,你会喜欢这个框架的。

为了使 Web 应用程序更加动态化,Angular.js、Backbone.js 和 Ember.js 等前端 Javascript 框架已广受欢迎。 但是,这些框架通常需要后端应用程序才能发挥作用,因此它们与 Ruby on Rails 和 Django 等 Web 框架结合使用。

另一方面,Ruby 框架 Volt 能够管理后端和动态前端。 由于这两个功能都紧密集成到其核心中(事实上,Volt 更像是一种 MVVM 架构,利用了数据绑定的优势),它使开发人员能够快速构建这些应用程序。

开箱即用的一个非常酷的功能是 Volt 的实时功能。 如果您曾经制作过实时应用程序,您就会知道该过程可能具有挑战性——您可能实现了 AJAX 轮询、Web 套接字、服务器发送事件 (SSE),甚至使用了外部服务,从而增加了应用程序的复杂性,甚至产生了额外的成本. 与其他框架不同,Volt 与服务器保持连接(通过 Web 套接字),因此它不会为每个操作发出 Ajax 请求,而是立即将更改推送到所有客户端。 无需任何配置即可工作。

认识 Volt,一个用于动态应用程序的有前途的 Ruby 框架

使用 Volt 创建聊天应用程序

在这个 Ruby 框架教程中,我将带您完成使用 Volt 创建实时应用程序的过程,以及比聊天应用程序更好的方式来展示其功能,因为聊天仍然是实时应用程序的第一大用例。

首先,让我们安装 Volt 和 MongoDB。 后面的过程就不详细介绍了:

 gem install volt brew install mongodb
 mkdir -p /data/db

(创建数据库路径)

 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 添加到参数中,这样我们就可以知道哪个已被选择,并添加一个名为“活动”的类,我们可以稍后对其进行样式设置。

现在让我们在控制器中创建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_conversationsend_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 to ''所以我们清空输入字段。

我们可能还想将该行添加到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 绝对值得一试

尽管 Volt 框架不像大多数流行的 Ruby 框架那样成熟和健壮,这些框架已经存在多年(目前 Volt 仍处于测试阶段),但值得考虑和研究。

如果您有兴趣,可以使用这个 Ruby 框架教程来体验一下 Volt。 密切关注进一步的发展,因为即使在这个开发的早期阶段,Volt 看起来也是一个非常有前途的 Ruby 框架。

有很多很酷的新功能正在筹备中,我很确定 Volt 在接下来的几年里会变得更加重要,因为越来越多的人开始尝试它。 由于许多创新功能,许多开发人员可能会爱上 Volt 并将其用于他们的下一个 Ruby 项目。