[Rails] 使用 asdf 将 Rails 升级到最新的 Ruby 3.2.0

使用 asdf 将 Rails 升级到最新的 Ruby 3.2.0

Ruby 3.0.2 已经在2022年12月25日正式发布。主要的改进有生产就绪的 YJIT 和开始对基于 WASI 的 WebAssembly (Wasm) 支持。

其中 YJIT 据说比 3.1 更快,内存开销大约是 3.1 的 1/3,Shopify Ruby 团队已经在生产工作负载上对 YJIT 进行了一年多的测试,证明非常稳定,非常值得在 Rails 项目中使用。

Ruby 3.0.2 发布说明参见:
英文版:Ruby 3.2.0 Released - https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-released/
中文版:Ruby 3.2.0 发布 - https://mp.weixin.qq.com/s/FhoSsyMz7-iZD7Z1dqLLnw[Ruby] Ruby 3.2.0 发布 | CloudoLife - https://cloudolife.cn/2022/12/31/Programming-Language/Ruby/Ruby-3-2-0-Released/

本文介绍如何将现有的 Rails 项目的 Ruby 版本升级到最新 3.2.0 版本。

项目背景

现有项目基于 Ruby 3.0.2 和 Rails 6.1。其中 Ruby 版本由 asdf 来安装和管理。首先确认软件版本情况:

1
2
3
4
5
6
7
8
$ asdf version
v0.11.1

$ ruby -v
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-darwin20]

$ rails -v
Rails 6.1.3.1

提示
asdf 是一个编程语言、框架和软件工具(如 Dart, Elixir, Flutter, Golang (Go), Java, Node.js, Python, Ruby 等)统一的版本管理器。
关于 asdf 更多信息,请参考Getting Started | asdf - https://asdf-vm.com/guide/getting-started.html
关于 asdf Ruby 插件,请参考GitHub - asdf-vm/asdf-ruby: Ruby plugin for asdf version manager - https://github.com/asdf-vm/asdf-ruby

前提条件

在升级之前建议先做好以下准备工作:

  • 评估新版本兼容性,仔细阅读关于新版本兼容性相关问题,认真评估新版本升级可能对项目代码和数据的影响。

  • 准备测试套件,提前准备好回归测试代码套件和自动化测试环境,用于版本升级后执行自动化测试。

  • 备份代码和数据,为避免升级影响到项目代码和数据,需要升级之前备份好项目代码和数据。万一升级失败,可以回滚代码和数据。

安装 Ruby 3.2.0 版本

使用 asdf 安装 Ruby 3.2.0 版本

1
2
3
4
5
6
7
8
9
# 更新 asdf 的 Ruby 插件
$ asdf plugin update ruby

# 安装 Ruby 3.2.0 版本
$ asdf install ruby 3.2.0

# 检查 asdf 安装 Ruby 版本
$ asdf list ruby | grep 3.2.0
3.2.0

配置 asdf 使用 Ruby 3.2.0 版本

创建或修改 .tool-versions 文件

1
2
3
4
# ~/.tool-versions

- ruby 3.0.2
+ ruby 3.2.0

检查 Ruby 版本

现在最新 Ruby 3.2.0 版本已经生效。但没有默认开启 YJIT 特性。

1
2
$ ruby -v
ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-darwin22]

通过传递参数 --yjit 启用 YJIT 特性。注意输出版本已经带有 +YJIT

1
2
$ ruby -v --yjit
ruby 3.2.0 (2022-12-25 revision a528908271) +YJIT [x86_64-darwin22]

(推荐)通过环境变量 RUBY_YJIT_ENABLE=1 启用 YJIT 特性,适合启用 Rails 等 Ruby 应用。

1
2
$ RUBY_YJIT_ENABLE=1 ruby -v
ruby 3.2.0 (2022-12-25 revision a528908271) +YJIT [x86_64-darwin22]

Rails 项目使用 Ruby 3.2.0 版本

首先修改 Gemfile 文件以使用 Ruby 3.2.0 版本

1
2
3
4
# Gemfile

- ruby '3.0.2'
+ ruby '3.2.0'

运行 bundle update 更新 Gemfile.lock

1
bundle update

回归测试

记得运行回归测试验证项目功能是否工作正常。

1
2
3
4
$ rails test

# 开启 YJIT 的回归测试
$ RUBY_YJIT_ENABLE=1 rails test

运行

回归测试通过后,启动 Rails 应用

1
2
3
4
5
6
7
rails s

# 开启 YJIT 的启用
$ RUBY_YJIT_ENABLE=1 rails s

# 或通过 puma 启动
$ RUBY_YJIT_ENABLE=1 puma -C config/puma.rb

常见问题

升级过程中遇到的主要问题是,因为历史原因 Gemfile 文件未锁定依赖 gem 的版本。执行 bundle update 过程中触发某些 gem 升级到最新版本,与项目原有代码不兼容导致报错。

最佳实践
强烈建议后续根据 Gemfile 最佳实践锁定各 gem 的具体版本。如 gem 'sidekiq', '6.2.1'

cannot load such file – sidekiq/util (LoadError

1
2
$ rails s
~/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/bootsnap-1.15.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:17:in `require': cannot load such file -- sidekiq/util (LoadError

因为 Gemfilesidekiq 未锁定版本,bundle update 导致 sidekiq 意外升级导致的问题。

解决办法:在 Gemfilesidekiqsidekiq-cron 锁定版本。

1
2
3
gem 'sidekiq', '6.2.1'

gem 'sidekiq-cron', '1.2.0'

Cannot load database configuration: Alias parsing was not enabled. To enable it, pass aliases: true to Psych::load or Psych::safe_load. (Psych::AliasesNotEnabled)

1
2
$ rails s
~/.asdf/installs/ruby/3.2.0/lib/ruby/3.2.0/psych/visitors/to_ruby.rb:432:in `visit_Psych_Nodes_Alias': Cannot load database configuration: Alias parsing was not enabled. To enable it, pass `aliases: true` to `Psych::load` or `Psych::safe_load`. (Psych::AliasesNotEnabled)

因为 Gemfilepsych 未锁定版本,bundle update 导致 psych 意外升级导致的问题。

解决办法:在 Gemfilepsych 锁定版本。

1
gem 'psych', '~> 3.3.4'

提醒
请参考 File: README — Puma master - https://msp-greg.github.io/puma/#quick-start 了解更多关于 Puma 用法。

参考链接

[1] Ruby 3.2.0 Released - https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-released/

[2] Ruby 3.2.0 发布 - https://mp.weixin.qq.com/s/FhoSsyMz7-iZD7Z1dqLLnw

[3] [Ruby] Ruby 3.2.0 发布 | CloudoLife - https://cloudolife.cn/2022/12/31/Programming-Language/Ruby/Ruby-3-2-0-Released/

[4] Bundler: The best way to manage a Ruby application’s gems - https://bundler.io/guides/gemfile.html

[5] Home | asdf - https://asdf-vm.com/

[6] GitHub - asdf-vm/asdf-ruby: Ruby plugin for asdf version manager - https://github.com/asdf-vm/asdf-ruby

[7] Ruby 3.2’s YJIT is Production-Ready (2023) - https://shopify.engineering/ruby-yjit-is-production-ready

[8] A Fast, Concurrent Web Server for Ruby & Rack - Puma - https://puma.io/