个性化阅读
专注于IT技术分析

Rails 6的功能:新增功能和重要性

本文概述

正如大多数Ruby on Rails爱好者可能意识到的那样, Rails 6即将推出, 并带来了许多热切期待的功能和更改。本文的目的是使你熟悉Rails 6中添加的关键功能, 并概述它们如何帮助你改善应用程序, 从而节省宝贵的开发时间。

对于初学者, 请记住Rails 6需要Ruby 2.5+和升级的数据库。因此, 请确保你有计划相应地升级你的系统, 以防你尚未这样做。

那么这些新功能是什么?以下是你可能会继续使用的Rails 6关键功能的简要概述:

在Rails 6中测试

作为专业的Ruby on Rails开发人员, 我们旨在确保最大程度地覆盖我们的代码。但是, 当我们的测试用例变得”繁重”时, 测试就变成了乏味的活动, 我们不得不等待几分钟甚至几小时才能执行测试用例。

平行测试

好吧, Rails 6在这里有一个答案。它在ActiveSupport :: TestCase中添加了并行化方法, 该方法使你可以将测试套件与分支进程并行化。

因此, 需要并行化测试过程的步骤是将其添加到test_helper.rb中:

parallelize(workers: 2)

或者, 我们可以替换以前使用的命令来运行测试。例如, 现在可以用PARALLEL_WORKERS = 15 rails test OR PARALLEL_WORKERS = 15 rspec规范代替bin / rails test OR bin / rspec规范。

因此, 你可以更改用于在Travis, Gitlab, CircleCI等不同CI平台上运行测试套件的命令。

在创建/销毁每个进程时, 还会有钩子, 可以如下使用:

class ActiveSupport::TestCase
  parallelize_setup do |worker|
    # setup databases
  end
 
  parallelize_teardown do |worker|
    # cleanup databases
  end
 
  parallelize(workers: :number_of_processors)
end

注意:如果你想了解更多信息, 可以查看《 Rails指南》以获取更多详细信息。

动作电缆测试

自从我们谈论有效的测试以来, 我们还了解了Action Cable(Rails 5最重要的功能之一)如何得到改进。现在可以在任何级别上测试”动作电缆”:连接, 频道和广播。

连接测试旨在检查是否正确分配了连接标识符或是否拒绝了任何不正确的连接请求:

class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
  test "connects with params" do

    connect params: { user_id: 42 }
    OR
    cookies.signed[:user_id] = "42"
    connect

    assert_equal connection.user_id, "42"
  end
 
  test "rejects connection without params" do
    assert_reject_connection { connect }
  end
end

可以编写频道测试来检查用户是否可以订阅频道并且该频道具有流:

class ChatChannelTest < ActionCable::Channel::TestCase
  test "subscribes and stream for room" do
    # Simulate a subscription creation by calling `subscribe`
    subscribe room: "15"
 
    # You can access the Channel object via `subscription` in tests
    assert subscription.confirmed?
    assert_has_stream "chat_15"
  end
end

可以如下测试广播到频道:

# app/jobs/chat_relay_job.rb
class ChatRelayJob < ApplicationJob
  def perform_later(room, message)
    ChatChannel.broadcast_to room, text: message
  end
end
 
# test/jobs/chat_relay_job_test.rb
require 'test_helper'
 
class ChatRelayJobTest < ActiveJob::TestCase
  include ActionCable::TestHelper
 
  test "broadcast message to room" do
    room = rooms(:all)
 
    assert_broadcast_on(ChatChannel.broadcasting_for(room), text: "Hi!") do
      ChatRelayJob.perform_now(room, "Hi!")
    end
  end
end

注意:有关如何测试的更多提示, 请参见此处。

批量插入和向上插入

在某个时候, 我们所有人都需要一次性插入多个记录, 并且这样做时发现了许多解决方法。好吧, Rails 6提供了一个新方法, 即现成的新方法-insert_all, 类似于update_all。

它不会触发任何回调, 并且会执行一个SQL查询。还有一个额外的方法upsert_all, 它允许你使用upsert操作, 该操作由Postgres等许多现代数据库公开。因此, 现在你可以减少插入查询, 并使代码更优化。另外, 告别以前使用过的宝石, 例如activerecord-import。

这些方法准备了一个INSERT SQL查询, 并且一个SQL语句被发送到数据库, 而没有实例化模型或调用Active Record回调和验证。当违反主键(唯一索引或唯一约束)时, 还可以定义标准, 并可以选择跳过或运行增补查询。

下面是一些示例:

result = Article.insert_all(
  [
    { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' }, #...snip...
  ], returning: %w[ id title ], unique_by: :index_articles_on_title_and_author
)


result = Article.upsert_all(
  [
    { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' }, { id: 1, .... }, # duplicate 'id' here
    { id: 2, .... }, { id: 3, .... }, # duplicate 'title' and 'author' here
    { id: 4, .... }, { id: 5, .... }, # duplicate 'slug' here
    { id: 6, .... }
  ]
)

方法插入, 插入!和upsert是insert_all, insert_all的包装器!和upsert_all。

注意:有一篇很好的文章讨论了有关不同数据库的批量查询。如果你需要其他信息, 请确保将其签出。

在多个数据库之间切换

许多大型应用程序将欣赏的主要功能之一就是:Rails 6最终为你的应用程序添加了对内置的, 随时可用的多个数据库的支持!

数据库之间的切换图

当然, 设计选择仍然是你的选择, 无论你是要将应用程序分解为多个微服务, 每个微服务具有一个单独的数据库, 还是采用整体式路由, 或者为你的应用程序添加多个只读副本。

但是, 具有以这种简单方式进行操作的能力有可能在开发方面节省大量时间。

因此, 这是新的database.yml文件的外观:

development:
  primary:
    database: my_primary_db
    user: root
  primary_replica:
    database: my_primary_db
    user: ro_user
    replica: true
  animals:
    database: my_animals_db
    user: root
  animals_replica
    database: my_animals_db
    user: ro_user
    replica: true

以下是指定如何切换到不同数据库的有趣方法:

class AnimalsModel < ApplicationRecord
  self.abstract_class = true

  connects_to database: { writing: :animals_primary, reading: :animals_replica }
end

class Dog < AnimalsModel
  # connected to both the animals_primary db for writing and the animals_replica for reading
end

这是官方的GitHub页面, 也有很好的文档记录。我个人很期待在将来的Rails更新中也具有数据库分片功能(类似这样)。

动作邮箱

Rails 6的另一个有趣功能是添加了Action Mailbox, 该功能增加了将传入电子邮件路由到控制器(如邮箱)以在Rails中进行处理的功能。

Action Mailbox具有Mailgun, Mandrill, Postmark和SendGrid的入口。你还可以直接通过内置的Exim, Postfix和Qmail入口处理入站电子邮件。现在, 你可能无需详细说明就可以想象潜在的好处。它可能是直接处理来自服务台的邮件, 以自动化支持通知单-Rails 6允许客户直接通过电子邮件进行回复, 甚至更多。地板是开放的, 供你浏览此功能并提出一种适合你的应用程序的方法。

这是一个了解如何使用操作邮箱的小示例:

COMMENTS_REGEX = /^comment\+(.+)@example\.com/i

# app/mailboxes/application_mailbox.rb
class ApplicationMailbox < ActionMailbox::Base
  routing COMMENTS_REGEX => :comments
end

# app/mailboxes/comments_mailbox.rb
class CommentsMailbox < ApplicationMailbox
  def process
    user = User.find_by(email: mail.from)
    post_uuid = COMMENTS_REGEX.match(mail.to)[1]
    
    post = Post.find_by(uuid: post_uuid)
    post.comments.create(user: user, content: mail.body)
  end
end

此外, 配置电子邮件的新方法如下(以Sendgrid为例):

# config/environments/production.rb
config.action_mailbox.ingress = :sendgrid

使用Rails凭证:编辑可将密码添加到你的应用程序的加密凭证中action_mailbox.ingress_password下, 其中Action Mailbox会自动找到该密码:

action_mailbox:
  ingress_password: …

配置SendGrid入站解析, 以使用用户名actionmailbox和你先前生成的密码将入站电子邮件转发到/ rails / action_mailbox / sendgrid / inbound_emails。如果你的应用程序位于https://example.com, 则应使用以下URL配置SendGrid:

https://actionmailbox:[email protected]/rails/action_mailbox/sendgrid/i

如果你想进一步探索, Rails在这里已经有指南。

计时器

Zeitwerk是Ruby的新代码加载器。在传统的文件结构下, Zeitwerk可以按需加载项目的类和模块, 这意味着你无需为自己的文件编写require调用。要在Rails 6中启用它, 可以执行以下操作:

config.autoloader = :zeitwerk

你可以在此处阅读有关Zeitwerk的更多信息。

优化器提示

你担心某些查询执行时间太长吗?好了, 现在你也可以为查询定义超时。

如果查询执行时间比正常时间长, 以下语句将引发StatementTimeout异常:

User.optimizer_hints("MAX_EXECUTION_TIME(5000)").all

它受MySQL支持, 因此你必须研究数据库是否支持它。

截断数据库

播种数据呢?以下语句将截断所有数据库表, 然后你可以继续播种数据:

rails db:truncate_all  

无需再删除数据库作为种子。你可能会同意这是一个优雅而快捷的解决方案。

动作文字

对于许多使用”所见即所得”编辑器的应用程序来说, 另一个值得注意的功能可能是在Rails 6应用程序中增加了对Trix编辑器的支持。对于许多项目而言, 这无疑是一个很好的升级/添加。

大多数WYSIWYG HTML编辑器的范围都很广泛-每个浏览器的实现都有自己的错误和怪癖, 而JavaScript开发人员则只能解决不一致问题。 Trix通过将contenteditable视为I / O设备来避免这些不一致:当输入进入编辑器时, Trix将该输入转换为对其内部文档模型的编辑操作, 然后将该文档重新提供给编辑器。这使Trix可以完全控制每次击键后发生的情况。

安装:

rails action_text:install

# app/models/message.rb
class Message < ApplicationRecord
  has_rich_text :content
end

你可以在此处的官方文档中进一步详细了解”操作文本”。

安全

没有一些安全性增强, 就不能完成任何认真的升级。同样, Rails 6在安全方面也不令人失望。第一个值得注意的安全性升级是添加了对主机授权的支持。

主机授权是一种新的中间件, 它通过明确允许主机将请求发送到主机来防御DNS重新绑定攻击。这意味着你可以定义可以访问应用程序的主机。

另一个安全升级旨在阻止试图复制cookie的签名/加密值并将其用作另一个cookie值的攻击。通过将cookie名称存储在目的字段中, 然后将其与cookie值一起签名/加密来实现。然后, 在服务器端读取时, 我们验证cookie名称并丢弃所有受攻击的cookie。启用action_dispatch.use_cookies_with_metadata以使用此功能, 该功能将写入具有新用途和过期元数据的cookie。

Webpack作为默认捆绑器

作为许多用于前端开发的现代JavaScript框架的事实上的标准, Rails 6通过webpacker gem将Webpack添加为默认的JavaScript捆绑器, 从而取代了Rails Asset管道。这是一个相对简单的补充, 我们将不赘述。足以说Webpack将为过度工作的前端开发人员带来一些缓解。

防止竞争条件

Rails 6有一个新方法, 用于防止代码中的SELECT / INSERT竞争条件(我相信许多读者在扩展项目时都会遇到竞争条件的不幸)。如果你需要其他信息, 这是GitHub线程。

基础表必须具有使用唯一约束定义的相关列。虽然我们避免了来自#find_or_create_by的SELECT→INSERT之间的竞争条件, 但实际上, 我们在INSERT→SELECT之间存在另一个竞争条件, 如果这两个语句之间的DELETE由另一个客户端运行, 则可以触发该竞争条件。但是, 对于大多数应用程序来说, 这是一个条件, 我们极少遇到这种情况。

Rails 6中的凭证

自Rails 5.2以来, 凭据已被命名为一种新的” Rails方式”, 用于处理敏感信息, 并有望一劳永逸地消除臭名昭著的.env文件。使用凭据, 可以将第三方服务的加密密钥直接检查到源控件中。

但是, 到目前为止, Rails在所有环境中都使用相同的加密文件, 这使得处理开发和生产中的不同密钥变得有些棘手, 尤其是在处理大型项目和旧代码时。

在Rails 6中, 最终通过支持每个环境的凭据解决了这一问题。同样, 可以在官方GitHub线程上探索更多细节。

Rails 6是一个很好的更新吗?

是的, 事实上, Rails 6可以说是一次重大更新, 尽管很少有人称其为改变游戏规则的人。由于Ruby on Rails已经存在了很多年, 很少有人期望进行革命性的改变, 但是它的第六种形式带来了很多东西。

在Rails 6中推出的某些功能似乎是次要的改进, 而其他功能则有可能节省大量开发时间, 提高安全性, 健壮性等。底线:Rails已经成熟, 许多开发人员对它的未来充满热情, 并且随着Rails 6的发布, 它变得更好了。

当然, 此Rails 6功能列表并不完整, 要查看完整的更改集, 你需要检出更改日志。此外, 你还应考虑许多弃用方法。最后, 如果你坚持要进行每个更改并自行更新, 请阅读完整的发行说明。

赞(0)
未经允许不得转载:srcmini » Rails 6的功能:新增功能和重要性

评论 抢沙发

评论前必须登录!