はじめに
昔開発した個人開発のポートフォリオ(バージョン Rails 6.1)を、最新の Rails 8.1 までアップデートを行ったので、その記録を残しておこうと思います。
なお、Rails をメジャーアップデートする方法として、「Rails 8 で新規アプリを作り、そこにコードを移植する」というやり方もあります。
今回の個人ポートフォリオは小規模なのでその方法でもありだったと思いますが、
今回は学習目的も踏まえて Rails8.1 まで段階的に
6.1 → 7.0 → 7.1 → 7.2 → 8.0 → 8.1
のような形で段階的にアップデートするする方針でアップデートを行いました。
アップデート前の構成
- Rails: 6.1.5
- Ruby: 3.1.1
- 環境: Docker
- テスト: RSpecあり
この状態から、最新の Rails 8.1 まで上げるのがゴールになります。
アップデート方針
今回のアップデートでは以下の記事がとても参考になりました。
上記の記事のやり方に倣って
- Rails以外の gem をまず最新のバージョンにアップデートする
- その後 Railsのバージョンを段階的に上げていく
という方針をとっています
また、1ステップ進めたら必ず bundle exec rspec を実行し、壊れていたらその都度直す方針で実施します。
Step 1:まず Rails 以外の Gem をアップデート
まずRails以外のgemのバージョンを上げることを行いました。
# Railsのバージョンを固定する
-gem 'rails', '~> 6.1.5'
+gem 'rails', '6.1.5'
Rails のバージョンを固定して bundle update を実施
root@3955839f1c4f:/myapp# bundle update
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies........................................................................................................................................................
(中略)
Using fog-aws 3.33.1 (was 3.14.0)
Using actiontext 6.1.5
Using actionmailbox 6.1.5
Using rails 6.1.5
Bundle updated!
1 installed gem you directly depend on is looking for funding.
Run `bundle fund` for details
アップデート成功
ここでRspecでエラー発生
RSpec を実行すると、以下のようなエラーが発生。
An error occurred while loading ./spec/system/users_spec.rb.
Failure/Error: require_relative '../config/environment'
NameError:
uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger
Logger::Severity.constants.each do |severity|
原因としては、以下の記事で記載されているように、 Railsがv7.1.0以前の場合
concurrent-ruby というgemのバージョンが1.3.4 より高いと発生するようなので
Gemfileに gem 'concurrent-ruby', '1.3.4' を追記し concurrent-ruby のアップデートを行ってみます。
+gem 'concurrent-ruby', '1.3.4'
root@3955839f1c4f:/myapp# bundle update concurrent-ruby
アップデート完了後、再度 rspec を実行すると今度は成功
Step 2:Rails 6.1 のパッチバージョンを最新へ
次に、Rails 6.1 の中で最新版まで上げます。
# Railsのバージョンを固定する
-gem 'rails', '~> 6.1.5'
+gem 'rails', '6.1.7.10'
root@3955839f1c4f:/myapp# bundle update rails
root@3955839f1c4f:/myapp# bundle exec rspec
これは何事もなく成功しました
Step 3:Rails 7.0 にアップデート
いよいよRails7にアップデートします。
# Railsのバージョン7.0に変更
-gem 'rails', '6.1.7.10'
+gem 'rails', '~> 7.0.0'
root@3955839f1c4f:/myapp# bundle update rails
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies.................................................................................................
(中略)
Bundler could not find compatible versions for gem "railties":
In Gemfile:
rails (= 7.0.0) was resolved to 7.0.0, which depends on
railties (= 7.0.0)
rails-i18n (~> 6.0) was resolved to 6.0.0, which depends on
railties (>= 6.0.0, < 7
アップデート失敗
rails-i18n のバージョンが6のままだったので 7 にして再びアップデート
# バージョン6固定で記載されていたため、7に変更
-gem 'rails-i18n', '~> 6.0'
+gem 'rails-i18n', '~> 7.0'
root@3955839f1c4f:/myapp# bundle update rails
今度は成功
Rails 7.1 / 7.2:基本的には同じ流れ
Rails 7.1、7.2 も同様にアップデート。
- Rails のバージョンを上げる
bundle update railsbundle exec rspec- 壊れたところを直す
RSpec 周りでは、fixture API の変更 や 例外扱いの変更 などの変更があり、
エラーがいくつか発生しました。
エラーについては以下と同様の内容であったため、詳細な内容についてはここでは省略します。
Ruby のバージョンをアップデート
最後にRailsを8に上げたいところですが
Rails 8 は Ruby 3.2以上が必要で、今動いているバージョンは3.1だったのでまずRubyをアップデートしました。
もし、仮にRailsを8にアップデートしようとしてもRubyのバージョンが違うためアップデートはできません。
root@3955839f1c4f:/myapp# bundle update rails
Fetching gem metadata from https://rubygems.org/........
Resolving dependencies...........
rails (~> 8.0.0) was resolved to 8.0.4, which depends on
Ruby (>= 3.2.0)
自分は Dockerイメージのslimのrubyを使っていたため
そのバージョンを変更して再ビルドを行います。
-ARG RUBY_VERSION=3.1.1
+ARG RUBY_VERSION=3.4.8
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
Gemfileのrubyのバージョンを指定する箇所も修正します。
-ruby '3.1.1'
+ruby '3.4.8'
docker compose build でビルドするも失敗
どうやら、ruby3.2以上では libyaml が必要みたいなので
Dockerfileに apt install libyaml-dev の記載も追加して再ビルドします
今度はビルド成功
Rails 8.0 / 8.1 & 最終調整
Rubyのバージョンアップができたので、Railsを 8.0、8.1 にアップデートを行います。
enum の書き方が変わるなど、いくつか修正内容はありましたが
特に大きな問題もなくアップデートできました。
- enum :role { general: 0, admin: 1, guest: 2 }
+ enum :role, { general: 0, admin: 1, guest: 2 }
最後に他の gem を再び最新のバージョンにするのも含めて
最初の方に追加した gem 'concurrent-ruby', '1.3.4' の記載も
このRailsのバージョンではもう不要なので削除して bundle update しておきます。
-gem 'concurrent-ruby', '1.3.4'
振り返りとまとめ
最終的に、以下の構成までアップデートすることができました。
- Rails: 6.1 → 8.1
- Ruby: 3.1 → 3.4
Rails 本体のアップデートには
大変そうというイメージを持っていましたが
思っていたよりもスムーズに進めることができました。
今回やらなかったこと
今回は 「アップデートすること」自体を目的にしていたため、
フロントエンド周りの構成は大きく変えていません。
- Webpacker は 引き続き使用
-
rails-ujsも そのまま利用
Rails 7 以降では Hotwire(Turbo / Stimulus)や Importmap など、
新しい選択肢が用意されていますが、
今回はそこまで踏み込まず、既存の構成をなるべく維持する方針にしました。
Hotwire への移行や構成の刷新については、
また別の機会に試して、別記事として書くかもしれません。