Upgraded Ruby on Rails from v4.2.4 to v5.1.4

こんにちは、エンジニアの神山です。
今年の1月に弊社アプリケーションで使用しているReactをFiber(v16)にアップグレードしました。
そしたら今度はRuby on Railsのアップグレードもすることになり、先日に無事アップグレードが完了したのでそのことについて書きました。

Railsは弊社の基盤フレームワークなので、慎重に確認と修正をしながら進めていきました。

詳細事項

  • Rubyバージョン: 2.3.3
  • Railsバージョン: 4.2.4 -> (5.0.6) -> 5.1.4
  • 実施期間: 2018年2月

手順

手順は以下の通りです。これらを追って説明していきます。

  • テストのカバレッジを上げる
  • すべてのGemのバージョンアップ
  • Railsのアップデート情報の検索
  • Railsのバージョンを5.0.6に上げる
  • Railsのバージョンを5.1.4に上げる
  • リリース

テストのカバレッジをあげる

これはGemやRailsのアップグレードをする際に、現在のコードがアップグレードしてもバグを起こさないか見つけるために行います。特に後方互換性がないアップグレードの時にとても役に立ちます。
今回のようなメジャーバージョンアップだと非推奨や使用不可になったコードが沢山出てくるのですが、テストの時点でほぼ気づくことが出来ました。

弊社は普段からテストを書くことを習慣にしていて、カバレッジは常に約95%あたりをキープしております。今回のアップグレードでも95%あれば十分であると判断したため、テストは追加で書かずにすみました。

カバレッジの目安はアプリケーションやチームによって変わってくると思うので一概には言えませんが、テストケースが十分にあるということは改めて大切だと思いました。

すべてのGemのバージョンアップ

一般的にGemはRubyRailsのバージョンがあがると追随してアップグレードされます。そのためRails5系の環境に沿ったGemを使用するべく、全てのGemのアップグレードも行います。

ただ注意として、そのGemの開発者がアップグレードに追随していないこともあります。するとRails5系で使いたいのに使えない、Rails4系までしか動かないとかも起こります。

そのときは同じ機能を持つGemで開発が活発なものを探すか、自分でパッチをあてないといけません。ただパッチをあてるとその瞬間から自分たちでそのGemを管理していかないといけなくなるので、注意と覚悟が必要です。
そのため信頼できる別のGemを探すほうがアプリケーションの開発に集中できる状態を保てるので、入れ替えのコストはかかりますが適切な選択だと思います。

ちなみにRefileというGemを使用しているのですが、アップグレードに追随していませんでした。この記事の下に詳しく書いておきます。

Railsのアップグレード情報の検索

アップグレードの情報を得るため、ドキュメントを予め読んでおくのは大切です。何かエラーが出たときに解決がスムーズになります。そのため変更点をまとめておくといいと思います。

私は以下のドキュメントを読みました。

Rails公式のリリースノートとアップグレードガイドの2つは絶対に読んでおくべきだと思います。

Railsのバージョンを5.0.6に上げる

今回のアップグレードはRails5.1系がゴールですが、一度Rails5.0系にアップグレードしてからRails5.1系にアップグレードしました。

理由は以下の通りです。

  • メジャーバージョンのアップグレードは一般的に規模の大きいアップグレードで、仕様が大きく変わる可能性があり、アプリケーションが最新のメジャーバージョンに対応できるか確認するため。
  • Rails4.2系からRails5.1系に一気にあげると変更点が多くコードの変更量も多くなるので、エラーが起きたときに原因がわかりにくくなってしまうため。
  • Rails5.1系へのアップグレードが現実的に難しいとわかっても、Rails5.0系へのアップグレードは出来る可能性があるため。

Railsはマイナーバージョンのアップグレードでも大きくコードが変更されることもあるので、段階的にアップグレードすることにしました。特に4系から5系はConfig周りの変更も多いので、慎重を期したほうが良いと思います。

Railsのバージョンを5.1.4に上げる

Rails5.0.6が正常に動いたので、そこからRails5.1.4へのアップグレードを行いました。ちなみにこのアップグレードの最中にRails5.1.5がリリースされたので、一度Rails5.1.5へのアップグレードを試みました。しかし正常に動作しなかったので最終的にはRails5.1.4になりました。こちらも記事の下に起きたことを書いておきます。

Rails5.0系からRails5.1系への変更もなかなかの量があり大変でした。特にActiveRecordまわりのメソッドが非推奨になったり新しく追加されたりしたので、Modelを念入りに確認しました。

アップグレード時に大変だったこと

RefileというGemがRails5系に対応していない

Refileを使っているアプリケーションは注意が必要です。Refileのリリースブランチは2年前のものであるため、Rails4系の仕様になっております。 ただmasterブランチはRails5系の仕様になっているので、そちらを使用すれば問題ありません。

しかしRefileに関連するGemでrefile-s3refile-mini_magickを使用しているのですが、その2つで問題が起きました。
これらはRefileのアドオンのようなもので、内部でRefileを使用しております。しかし使用しているRefileはリリースブランチのバージョン(つまりRails4系)であったため、Rails5系の環境では動きませんでした。

そこで「同じ機能を持つGemで開発が活発なものに変える」か「そのGemのレポジトリをフォークしてパッチをあてて使う」の2つを考えました。

Refileはファイルアップローダーであり、同じ機能を持つGemは有名所だと以下の3つが見つかりました。

上2つは有名なGemですがShrineは初めてしりました。Refileのコアな開発者が作成したGemで、開発も盛んで現在のトレンドのようです。(細かな違いなどは比較記事がネット上にあるのでそちらを参考にしてください。)

ただ今回は「そのGemのレポジトリをフォークしてパッチをあてて使う」にしました。理由はRails5.2系からActiveStorageというファイルアップローダーの機能が搭載されるためです。
そのためRails5.2系にアップデートする段階で再度判断することにし、今回はパッチで対応しました。またあてるパッチの量も少なく済みそうであったことも理由の1つです。

ちなみにあてたパッチはGemfileのrefileの箇所です。

- gem "refile", github: "refile/refile"
+ gem 'refile', git: 'https://github.com/refile/refile', branch: 'master'

ここで注意しなくてはいけないのがRails5系との互換性です。当然ながらGemfileの中身を変更しても、Gemのコード自体が対応していないと使用することはできません。その為パッチをあてるときは、Gemの中身を一通り読んでおくべきだと思います。

Rails5.1.5が正常に動作しない

まだ原因の根源まではわかっていませんが、ActiveRecordで作るクエリの条件式に関連先のテーブルのものを使用するとエラーが起きました。

Hoge.includes(:fuga).where(fugas: { bool: true })

キャッシュの変更に悩まされる

Rails5系からActiveRecord::Relationにも.cache_keyというメソッドが実装されました。しかしActiveRecordで作るクエリの条件式に関連先のものを使用するとエラーが起きました。

Hoge.includes(:fuga).where(fugas: { bool: true}.cache_key
/ => ActiveRecord::StatementInvalid: PG::UndefinedTable

またView上で使用する際も同様のエラーになります。

- cache hoges do …
/ => ActiveRecord::StatementInvalid: PG::UndefinedTable

ちなみにActiveRecord::Relations#cache_keyは、他にも注意点があります。下のドキュメントがよくまとめられているので、一読しておくことをおすすめします。

techracho.bpsinc.jp

所感

今回のアップグレードを通して以下のことを学びました。

  • フレームワークの更新を常に把握する。
  • アップグレードはマイナーバージョンの安定版が出たら即行う。
  • テストは常に書く。

上の項目は普段から習慣付けるといいと思います。そうでないとアップグレードしようとしたときにつらい思いをすることになります。
場合によっては気づいたら最新のバージョンとコードが乖離しすぎてて、アップグレードは現実的に不可能なんてことにもなり兼ねません。

雑感ではありますが、アップグレードはなかなか出来ることでもないのでとてもいい経験になりました。

We’re Hiring

弊社ではWeb / ネイティブアプリエンジニアを募集しております。
ご興味がありましたらお気軽にご連絡下さいませ!
エンジニアの方、ぜひ情報交換しましょう!

www.wantedly.com

www.wantedly.com