Rails7升级攻略:迁移注意事项与常见问题解答

Rails 7 升级攻略:迁移注意事项与常见问题解答

Rails 7 带来了许多令人兴奋的新特性和改进,包括默认的 importmap、Hotwire(Turbo 和 Stimulus)、基于时间的加密消息签名器、异步查询加载等。 然而,从 Rails 6.x 升级到 Rails 7 并非总是一帆风顺的过程。本文将详细介绍升级过程中的关键注意事项、潜在的陷阱以及常见问题的解决方案,帮助你平稳地过渡到 Rails 7。

一、升级前的准备工作

  1. 备份!备份!备份! 在进行任何重大升级之前,务必对你的代码库、数据库和所有相关的配置文件进行完整备份。这是防止出现问题导致数据丢失的最重要步骤。

  2. 良好的测试覆盖率。 拥有高覆盖率的测试套件是成功升级的关键。确保你的测试能够捕获到潜在的回归问题。 运行完整的测试套件,并确保所有测试通过。

  3. 阅读官方升级指南。 Rails 官方提供了详细的升级指南(https://guides.rubyonrails.org/upgrading_ruby_on_rails.html),这是升级过程中的最佳参考。务必仔细阅读,并按照指南中的步骤操作。

  4. 评估 Gem 依赖。 检查你的 Gemfile 中的所有 gem 是否兼容 Rails 7。 使用 bundle outdated 命令查看哪些 gem 需要更新。 特别注意以下几类 Gem:

    • ORM (Object-Relational Mapping): 如 ActiveRecord (通常不需要特别关注,因为它与 Rails 紧密集成)。
    • 认证和授权: 如 Devise, Clearance, Pundit 等。 确保这些 Gem 都有兼容 Rails 7 的版本。
    • 前端框架/库: 如 Bootstrap, jQuery, Vue.js, React 等。 如果使用 Sprockets,某些库可能需要更新或迁移到 importmap。
    • 后台任务: 如 Sidekiq, Resque 等。
    • API 相关: 如 RABL, ActiveModel::Serializers (已被弃用) 等。
  5. 升级 Ruby 版本。 Rails 7 需要 Ruby 2.7.0 或更高版本,强烈建议使用 Ruby 3.0 或更高版本以获得最佳性能和新特性。 使用 rbenv, rvm 或其他 Ruby 版本管理器来管理你的 Ruby 版本。

  6. 小步快跑,逐步升级。 不要试图一次性完成所有升级步骤。 建议采用增量升级的方式,例如先升级到 Rails 6.1,解决所有 deprecation warnings,然后再升级到 Rails 7。

二、升级步骤

  1. 更新 Gemfile。Gemfile 中修改 Rails 版本:

    ruby
    gem 'rails', '~> 7.0'

  2. 运行 bundle update rails。 这将更新 Rails 及其依赖项。 可能会遇到一些冲突,需要手动解决。

  3. 运行 rails app:update。 这个命令会生成新的配置文件,并更新现有的配置文件。 它会询问你是否覆盖现有文件。 强烈建议逐个比较差异,并手动合并更改,而不是简单地覆盖。 特别注意以下文件:

    • config/application.rb: 检查 config.load_defaults 的设置。 Rails 7 默认是 7.0,这可能会改变一些默认行为。
    • config/environments/*.rb: 检查各种环境配置,例如缓存、日志等。
    • config/initializers/*.rb: 检查初始化文件,确保它们与 Rails 7 兼容。
    • config/routes.rb: 路由文件通常不需要大的改动,但是要关注 concerns 的使用。
    • bin/: Rails7 对 bin 目录下的文件进行了调整,比如 bin/dev 的引入,需要特别注意。
  4. 处理 Deprecation Warnings。 在升级过程中,你可能会遇到一些 deprecation warnings。 这些警告会告诉你哪些代码在未来的 Rails 版本中将被移除。 务必解决这些警告,以确保你的应用程序在未来版本中能够正常运行。

  5. 迁移数据库。 运行 rails db:migrate 来更新数据库 schema。 如果你的数据库迁移文件中有使用到旧版本 Rails 特性的代码,可能需要手动修改。

  6. 配置 Zeitwerk (代码加载器)。 Rails 6 默认使用 Classic 代码加载器,而 Rails 7 默认使用 Zeitwerk。 Zeitwerk 有更严格的命名约定。 如果你的应用程序没有遵循这些约定,可能会遇到加载错误。 运行 rails zeitwerk:check 检查是否有命名冲突。 解决这些冲突通常需要重命名文件或类。

  7. 选择 JavaScript 打包方式:importmap-rails (默认) 或 jsbundling-rails。

    • importmap-rails (推荐): Rails 7 默认使用 importmap-rails。 它允许你直接在浏览器中使用 ES 模块,而无需构建步骤。 这简化了前端开发流程。
    • jsbundling-rails: 如果你的应用程序使用了复杂的 JavaScript 构建流程,或者依赖于 Webpack、esbuild 或 Rollup 等构建工具,你可以选择使用 jsbundling-rails。 它允许你集成这些工具。

    如果选择 importmap-rails, 需要将 application.js 调整为使用 import 方式引入 JavaScript 代码。 如果选择 jsbundling-rails,你需要安装相应的 npm 包 (例如 webpacker,但 Webpacker 已不再维护,推荐使用 jsbundling-rails 配合 esbuild, rollup 或 webpack 使用)。

  8. 处理 Active Storage 的变化。 Active Storage 在 Rails 7 中有一些变化,包括默认的变体处理器从 MiniMagick 更改为 ImageMagickvips (如果可用)。 如果你的应用程序使用了 MiniMagick 特有的功能,可能需要进行修改。

  9. 处理 Action Cable 的变化。 Action Cable 的适配器配置略有变化。检查 config/cable.yml 文件。

  10. 其他可能的变化:

    • ActiveModel::Serializers 已被弃用。 如果你的应用程序使用了这个 gem,建议迁移到其他解决方案,例如 Fast JSON API 或直接使用 render json: ...
    • protect_from_forgery 的默认行为发生了变化。 现在默认使用 :prepend 选项,这可能会影响 CSRF 保护。
    • Sprockets 相关的改动。 如果你仍然使用 Sprockets,需要注意一些细微的改动。 强烈建议迁移到 importmap 或 jsbundling-rails。
    • Content Security Policy (CSP): Rails 7 增强了 CSP 的支持,可以更方便地配置 CSP 策略。

三、常见问题解答

  1. Q: 升级后,应用程序启动失败,并出现 LoadError: cannot load such file -- ... 错误。

    A: 这通常是由于 Zeitwerk 代码加载器引起的。 请检查以下几点:

    • 确保你的类名和文件名遵循 Zeitwerk 的命名约定。
    • 运行 rails zeitwerk:check 检查是否有命名冲突。
    • 检查你的 autoload_pathseager_load_paths 配置。
    • 确保你没有在初始化文件(config/initializers)中引用尚未加载的类。
  2. Q: 升级后,JavaScript 代码无法正常工作。

    A:

    • 如果你使用的是 importmap-rails,确保你的 application.js 文件正确地使用了 import 语句。 检查控制台是否有 JavaScript 错误。
    • 如果你使用的是 jsbundling-rails,确保你已经安装了相应的 npm 包,并正确配置了构建工具。
    • 如果你之前使用的是 Sprockets,可能需要手动将一些 JavaScript 代码迁移到 importmap-railsjsbundling-rails
    • 检查你的 JavaScript 代码是否与 Rails 7 引入的 Turbolinks 和 Stimulus 兼容。
  3. Q: 升级后,表单提交失败,并出现 CSRF 错误。

    A:

    • 确保你的表单中包含 CSRF token。 Rails 会自动在表单中插入一个隐藏的 <input> 标签,包含 CSRF token。
    • 检查你的 protect_from_forgery 配置。 Rails 7 默认使用 :prepend 选项。
    • 如果你使用了 JavaScript 来提交表单,确保你正确地发送了 CSRF token。
  4. Q: 升级后,Active Storage 无法正常工作。

    A:

    • 确保你已经运行了 rails db:migrate 来更新数据库 schema。
    • 检查你的 Active Storage 配置,例如 config/storage.yml
    • 如果你使用了 MiniMagick 特有的功能,可能需要进行修改,因为 Rails 7 默认使用 ImageMagickvips
  5. Q: 升级后,我的测试失败了。

    A:

    • 仔细检查测试失败的原因。 可能是由于 Rails 7 的行为变化,或者你的测试代码依赖于已弃用的功能。
    • 更新你的测试代码,以适应 Rails 7 的新特性和变化。
    • 确保你的测试覆盖了所有重要的代码路径。
  6. Q: 升级后,发现 bin/dev 文件不见了,该如何启动开发环境?
    A: Rails 7 使用 bin/dev 替代了之前分别启动 Rails server 和 webpack-dev-server (如果使用 webpacker) 的方式。 bin/dev 使用 Foreman 来管理多个进程。你需要安装 foreman gem (gem install foreman),然后通过 bin/dev 启动开发环境。

  7. Q: 升级后, 控制台出现关于 ActionView::Helpers::SanitizeHelper 的警告,该如何处理?

    A: Rails 7 对 sanitize helper 进行了更严格的限制。 如果你使用了自定义的 sanitizer 配置,可能需要进行调整。 检查你的代码中是否有直接使用 sanitize 方法的地方,并根据警告信息进行修改。

四、总结

升级到 Rails 7 是一个需要仔细规划和执行的过程。 通过遵循本文提供的指南,并仔细处理升级过程中的每个步骤,你可以最大程度地减少升级的风险,并顺利地迁移到 Rails 7,享受其带来的新特性和性能提升。 记住,备份、测试和逐步升级是成功升级的关键。 如果遇到问题,不要犹豫,查阅官方文档、搜索相关资料,或者在 Rails 社区寻求帮助。

THE END