Railsを5.2.3から6.0.1にアップグレードする手順

はじめに

Rails アップグレードする機会が直近何度かあったので手順を備忘録としてもアウトプットして残しておきます。
なお例として、Rails 5.2.3 から Rails 6.0.1 のアップグレードを扱っています。

手元のMac環境はこちら

  • MacBook Pro (13-inch, 2019, Two Thunderbolt 3 ports)
  • macOS Mojava バージョン 10.14.6

心構え:なぜライブラリをアップデートするか

ざっと利点をまとめてみました。

  • 便利な機能がある
  • パフォーマンス向上
  • セキュリティの問題
  • 開発を補助する
  • 未来のチームのため

設定より規約(Convention over Configuration)という言葉があります。
開発者の決定すべきことを減少させ、単純にするが柔軟性は失わせないソフトウェア設計のことです。

これを可能にするのが各種ライブラリで、これらは定期的にアップデートされます。
その理由の多くは、便利機能の追加・パフォーマンス向上・セキュリティ改善等の利用者を考慮したものです。
この流れに追随することでプロダクト品質を保ち続けることができるのです。

手順①:公式のアップグレードガイドを読む

Railsガイドにはアップグレードの方法を説明しているページがあります。
アドバイスの他に、各バージョン毎の注意点が載っているので、まずはこのページを読みます。

Rails アップグレードガイド – Rails ガイド

手順②:テストカバレッジを高めておく

アップグレード作業によって既存コードの動作が変わりシステムエラーになる可能性が大いにあります。

テストカバレッジを高め、作業前後でテストグリーンを確かめることはメンテナンスコストを下げてくれます。
僕の携わるプロダクトでは、RSpec によるシステムスペックを中心にテストコードを拡充しました。
テストコード比だけが全てではないですが、テストコード比 1:0 ⇒ 1:4 までテストカバレッジを上げています。

before
after

テストコードがゼロの状態からカバレッジを上げるのは大変でしたが、一度出来てしまえばその後が絶対に楽になります。多大な恩恵を得られるのでテストは書いておきましょう。

手順③:dependabot で Rails 以外の gem をアップデートしておく

Rails 以外の gem が最新の Rails に対応していない状況で Rails 本体のバージョンを上げると、エラーが起きる可能性があります。
そこで、事前に Rails 以外の gem をアップデートしておくことが大切になるのですが、役に立つのが github に買収されて無料になった dependabot です。

dependabot は 利用している gem のバージョンに差分が生まれたらプルリクを作ってくれるボットです。

自動作成されたプルリクを確認するだけで、アップデートを容易に行うことが出来ますし、アップデート差分が小さくなるのでバグ等の影響も減らすことが出来ます。またプルリクには gem 本体の差分コミットや ChangeLog も抜粋されて掲載されるので gem のコードを読むきっかけにもなります。

簡単に設定面に触れておくと、こんな使い方をしています。

  • デイリーでアップデート対象を探す
  • Gemfile.lock 記載の情報でアップデート(Gemfile でバージョン固定していたらそれに従う)
  • auto-merge は行わずプルリクを作るだけに留める

setting1
setting2

手順④:Ruby のバージョンを最新にする

使用している Ruby のバージョンが古い場合は、Rails アップグレードの前に最新にしておきましょう。

# 2019年11月23日現在、Ruby の最新バージョンは 2.6.5 です
$ rbenv local 2.6.5

# Gemfile記載の Ruby バージョンを書き換え
-    ruby '2.6.3'
+    ruby '2.6.5'

# gem を再インストール
$ bundle

僕は、RuboCop と CircleCI を用いているのでこれらの設定ファイルに記載されている Ruby バージョンも変更します。Ruby バージョンアップでテストが通ることも確認しますが、僕はCircleCIに任せています。

手順⑤:Rails のアップグレード

ここからが本番です。今回は Rails 5.2.3 → 6.0.1 のメジャーアップデートを例に書きます。
(2019年11月23日現在、Rails の最新バージョンは 6.0.1 です)

Railsのメジャーバージョンを上げる

-    gem 'rails', '5.2.3'
+    gem 'rails', '6.0.1'

bundle update –conservative で Rails と依存関係にある gem だけ上げる

手順④までで Rails 以外の gem は全て最新にアップデートされているはずですが、念の為に coneservative オプションを用います。

$ bundle update --conservative rails

すると、このようにコンフリクトがおきるはずです。Rails をアップデートするためには依存関係にある actionview も上げないといけないと警告されているのです。(キャプチャは 6.0.0 →6.0.1 に挙げたときのものですが。。)

conesrvative

そこで、コマンドの後ろに actionview をつなげて再実行すると同じように別の gem がコンフリクトするはずです。これを繰り返していき、bundle update が成功するコマンドを見つけます。最終的に僕はこれで成功しました。

$ bundle update --conservative rails actionview activerecord actionpack activesupport railties activemodel

rails app:update

rails app:update を実行します。
新しいバージョンで必要になるファイル作成や、既存ファイルの変更を対話形式で行うことができます。

既存ファイルの変更方法は下記のように質問されるので、 Y/n/a/q/d/hのいずれかのキーを入力します。
僕は、d で diff を確認して、問題なければ Y で上書き更新する作業で進めています。

upgrade

Y で上書き更新すると、config 配下に行った独自設定が失われることが多いです。
その場合は sourcetree や git diff などで、消えてしまった差分設定を自力で戻していきます。

railsdiff.org を参考にして、残りの差分を解消する

rais app:upgrade は Gemfile などを更新対象にしないので、まだ差分が残る状態になることがあります。
その場合に使うのが http://railsdiff.org です。
このサイトでは Rails の各バージョンごとに、rails new した直後のファイルの diff を確認することができます。

今回の場合、以下のURLで Rails 5.2.3 と 6.0.1 の diff を確認できます。
これを参考に、upgrade コマンドの更新対象ではなかった Gemfile 等に更新があれば自力で差分を埋めていきます。
http://railsdiff.org/5.2.3/6.0.1

動作確認

サーバを立ち上げたり、テストを流したりして動作に不具合がないかを確かめます。

load_defaults の値を更新する

すべての動作が正常になったら、最後に config/application.rb の load_defaults を変更します。

-    config.load_defaults 5.2
+    config.load_defaults 6.0

ここまでをプルリクとして作成し、アップグレード対応作業をチームにレビューしてもらうことでデプロイすれば無事にアップグレード終了になります。

今回は以上です。

この記事の内容が役に立ったと思いましたら、SNSで記事を共有していただけますと幸いです。