9分钟阅读

轨道 6功能:什么'新的,为什么重要

作为顾问,Avant帮助为Chipotle,Seabotle,Healthengine,Deaveey等客户提供建立申请。

由于大多数Ruby在Rails Fans上可能意识到,Rails 6即将推出,并带来了一些热切期待的功能和变化。本文的目的是让您熟悉rails 6的关键功能,并概述它们如何帮助您更好地使您的应用程序更好,从而节省有价值的开发时间。

对于初学者,请记住Rails 6需要Ruby 2.5+和升级的数据库。因此,请确保您有计划升级系统,以防您已经完成了。

那么这些新功能是什么?这是一个快速回顾的钥匙栏6个功能,您可能正在前进的前进:

在Rails 6中测试

作为专业人士 Ruby在Rails开发人员上,我们的目标是确保为代码的最大覆盖范围。然而,当我们的测试用例变得“沉重”时,测试成为繁琐的活动,我们必须等待几分钟,甚至几个小时,只是为了获得执行的测试用例。

并行测试

Well, Rails 6 has an answer here. It has added a parallelize method to the ActiveSupport::TestCase which allows you to parallelize the test suite with forked processes.

So, what you need to do to parallelize the processes for your tests is add this to your test_helper.rb:

parallelize(workers: 2)

Alternatively, we can replace our previously used commands for running tests. For example, bin/rails test OR bin/rspec spec can now be replaced by PARALLEL_WORKERS=15 rails test OR PARALLEL_WORKERS=15 rspec spec.

因此,您可以更改用于在格拉维斯,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

笔记: 如果您想了解更多,您可以查看 轨道导轨 有关其他详细信息。

动作电缆测试

自从我们谈论高效测试以来,我们还了解如何采取动作电缆,轨道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

笔记: 有关如何测试的更多提示 这里.

散装插入和上升

At some point, we all need to insert multiple records in one go and have found many workarounds when doing so. Well, Rails 6 comes with a new method out of the box—insert_all, similar to update_all.

It won’t fire any callbacks and will execute a single SQL query. There is an additional method upsert_all which allows you to use the Upsert操作 which is exposed by many modern databases like Postgres. So now you can reduce your insert queries and make your code more optimized. Also, say goodbye to previously used gems like activerecord-import.

A single INSERT SQL query is prepared by these methods, and a single SQL statement is sent to the database, without instantiating the model, or invoking Active Record callbacks and validations. It is also possible to define criteria when a primary key—unique indexes or unique constraints are violated with an option to either skip or run upsert queries.

以下示例如下:

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, .... }
  ]
)

The methods insert, insert! and upsert are wrappers around insert_all, insert_all! and upsert_all, respectively.

笔记: 有一篇非常好的文章,讨论了不同数据库的批量查询。如果您需要其他信息,请确保您 一探究竟.

在多个数据库之间切换

其中一个主要功能许多大应用将会理解这是:Rails 6最终为您的应用程序添加了对多个数据库的支持,内置并准备好了,从框中出发!

数据库之间切换图

当然,设计选择仍然是您的,无论您是否要将应用程序分成多个微服务,每个都具有单独的数据库,或拍摄单片路由,或为您的应用程序添加多个读取副本。

但是,具有以这种简单的方式执行此操作的能力有可能保存 很多 在发展前沿的时间。

So, this is how your new database.yml file will look:

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更新中具有数据库分片功能(类似的东西) )。

行动邮箱

另一个有趣的铁轨6功能是添加的 行动邮箱,它增加了能力 路线传入的电子邮件 到控制器等邮箱用于在轨道中处理。

操作邮箱具有MailGun,MandRill,Postmark和Sendgrid的Inchresses。您还可以通过内置Exim,Postfix和Qmail Ingresses直接处理入站电子邮件。现在,您可能会想象潜在的好处而不更详细。它可能直接从帮助台处理邮件到自动化支持门票 - 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

Use rails credentials:edit to add the password to your application’s encrypted credentials under action_mailbox.ingress_password, where Action Mailbox will automatically find it:

action_mailbox:
  ingress_password: …

配置 Sendgrid入站解析 to forward inbound emails to /rails/action_mailbox/sendgrid/inbound_emails with the username actionmailbox and the password you previously generated. If your application lives at //example.com, you would configure SendGrid with the following URL:

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

如果您想进一步探索此情况,Rails已经有一个导游 这里.

Zeitwerk.

Zeitwerk.是Ruby的新代码加载程序。鉴于传统的文件结构,Zeitwerk按需加载您的项目的类和模块,这意味着您不需要编写要求呼叫您自己的文件。要在Rails 6中启用它,您可以执行以下操作:

config.autoloader = :zeitwerk

您可以阅读更多信息 Zeitwerk.在这里.

优化器提示

你担心你的一些询问时间太长了吗?嗯,现在你也有办法为您的查询定义超时。

The following statement will raise an StatementTimeout exception if the query takes longer than normal to execute:

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

它由MySQL支持,如果您的数据库支持它,您必须探索。

截断数据库

播种数据怎么样?以下语句将截断所有数据库表,然后您可以继续播种您的数据:

rails db:truncate_all  

不再删除您的数据库到种子。您可能会同意这是一个优雅快捷的解决方案。

行动文本

也许是与WYSIWYG编辑器一起玩的许多应用程序的另一个显着的功能是增加支持 Trix编辑器 本身进入Rails 6应用程序。这肯定是许多项目的良好升级/添加。

Most WYSIWYG HTML editors are enormous in scope—each browser’s implementation has its own set of bugs and quirks, and JavaScript developers are left to resolve the inconsistencies. Trix sidesteps these inconsistencies by treating contenteditable as an I/O device: When input makes its way to the editor, Trix converts that input into an editing operation on its internal document model, then re-renders that document back into the editor. This gives Trix complete control over what happens after every keystroke.

安装:

rails action_text:install

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

你可以探索 行动文本 在官方文件中进一步详细, 这里.

安全

没有一些安全增强,没有严重升级。 Rails 6也不会让人失望。第一个值得注意的安全升级是增加支持 主机授权.

主机授权是一种新的中间件,可防止 DNS Rebinding. 通过显式允许主机可以发送请求的攻击。这意味着您可以定义可以访问应用程序的主机。

Another security upgrade is meant to thwart attacks that attempt to copy the signed/encrypted value of a cookie and use it as the value of another cookie. It does so by stashing the cookie name in the purpose field which is then signed/encrypted along with the cookie value. Then, on the server-side read, we verify the cookie names and discard any attacked cookies. Enable action_dispatch.use_cookies_with_metadata to use this feature, which writes cookies with the new purpose and expiry metadata embedded.

WebPack作为默认的Bundler

与前端开发的许多现代JavaScript框架一样,Rails 6通过WebPacker Gem添加了WebPack作为默认JavaScript Bundler,更换了Rails资产管道。这是一个相对简单的加法,我们不会详细说明。足以说网吧将为过度劳累的前端开发人员带来一些救济。

防止竞争条件

轨道 6具有一种新方法,用于防止在我们的代码中选择/插入竞争条件(我相信许多读者在他们规模的项目中遇到竞争条件的不幸)。这里是 github螺纹 如果您需要其他信息。

The underlying table must have the relevant columns defined with unique constraints. While we avoid the race condition between SELECT → INSERT from #find_or_create_by, we actually have another race condition between INSERT → SELECT, which can be triggered if a DELETE between those two statements is run by another client. But, for most applications, that’s a condition we’re significantly less likely to hit.

轨道 6的凭据6

由于Rails 5.2的日子以来,凭据已被命名为新的“Rails Way”,以处理敏感信息,并承诺摆脱臭名昭着 .env. 文件一次和所有文件。使用凭据,可以直接检查第三方服务的加密密钥。

然而,到目前为止,Rails使用了所有环境的相同加密文件,这使得在开发和生产中处理不同的键,特别是在处理大项目和遗留代码时。

在Rails 6中,终于解决了对每个环境凭证的支持。再次,官方可以探讨进一步的详细信息 github螺纹.

rails 6一个好的更新?

是的,实际上Rails 6可以被描述为一个重大更新,虽然很少有人会称之为游戏更换者。由于Ruby在轨道上已经存在了几年,因此很少有人期待革命性的变化,但它的第六篇化身给桌子带来了很多。

在Rails 6中推出的一些功能似乎是轻微的改进,而其他功能则有可能节省大量的开发时间,提高安全性,鲁棒性等。底线:轨道成熟, 很多开发商对其未来仍然热烈 并且随着轨道6的释放,它甚至更好。

当然,这个Rails 6功能列表是不完整的,要查看完整的更改集,您需要查看更改内容。此外,您应该考虑很多弃用。最后,如果你坚持要换过每一次改变并更新自己,请阅读 全发布说明.

理解基础知识

Ruby在2019年仍然相关的Raby?

轨道比市场上的任何其他解决方案更相关。 Rails和Ruby都升级(Matz正在制作Ruby 3x)。 Rails 6带来了简单的技术,可以本地缩放应用。这仍然是许多像Github,Shopify,Basecamp等许多大玩家的可信选择。

我应该使用轨道吗?

答案取决于您的用例。它仍然是常规Web,电子商务,内容管理和许多其他类型的应用程序的最佳框架。它还减少了MVP开发时间,并且当您没有固定的想法或需要应用程序的快速原型时,这是一个很好的选择。

upsert是什么意思?

Upsert是一个数据库操作,意味着,如果数据库中已存在的记录已存在,则基于为操作提供的属性,如果记录不存在,则要更新该记录或创建新记录。 Upsert发生在单一的交易中,从而防止应用程序中的任何竞争条件。

并行测试有哪些优点?

我们已经看过该项目需要数小时只是运行测试用例。通过在不同的过程中运行一套测试用例,我们可以减少测试用例的运行时间。通过Rails 6并行测试,我们不必依靠外部服务并将其并行化我们的测试用例。