アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

いこレポのRailsを5.1.2から5.2.2にアップグレードしました

morishitaです。

Rails 6のリリースも見えてきたので、やっといこレポのRailsをアップグレードしました。

具体的には、Rails 5.1.2 → 5.2.2 のアップグレードを実施しました。それについて紹介します。

アップグレードまでの道のり

アップグレードはセオリー通り次のステップで進めました。

  1. テストカバレッジを上げる
  2. Railsのバージョンを保ったまま、他のgemをアップデートする
  3. Railsをアップグレードする

テストカバレッジを上げる

アップグレードの事前準備ですね。 いこレポでは RSpecでテストを実装しており、SimpleCovでカバレッジを計測しています。
これで計測できるのは行カバレッジですが、次のような状況なので拠り所としてよかろうと判断しました。

  • if文がむちゃくちゃ多い処理はない
  • あるif文による分岐の結果が次の分岐に影響するような処理も少ない

目標カバレッジは90%としました。それに対して計測値は約85%。

どこが足りてないのかと調べたらモデルスペックもある主要なモデルで計測されていないものがあります。

設定ミスもなさそうでした。 test-queueが原因かと思い、やめてみても結果は変わらず。
とりあえず、他にすべきことを先に片付けようとFactoryBot の DEPRECATION WARNING1に対応しました。

> DEPRECATION WARNING: Static attributes will be removed in FactoryBot 5.0. Please use dynamic attributes instead by wrapping the attribute value in a block

すると、何ということでしょう!カバレッジも一気に上がりました。
確認すると、計測されていなかったモデルのカバレッジが計測されています。

どうやらSimpleCov.startより先にロードされたクラスは測定対象にならないようです。
Factoryから静的属性の値として参照されているクラスは SimpleCov.start より先にロードされてしまうために測定対象から外れていたようです。
問題のモデルも定数のいくつかが静的属性の値として参照されていました。

それが動的属性に変更することにより最初にFactoryが利用されるときに評価されるようになったため SimpleCov.start よりあとでロードされ計測対象として扱われるようになったようです。

これによりカバレッジ92%を超え、目標をクリアしました。

gemをアップデート

準備は整ったので、どんどんgemをアップデートしていきました。 もともと、gemのアップデートをサボりがちだったので古くなっているものが結構多かったです。

本番環境の動作に影響が少ないdevelopmentグループとtestグループのgemからアップデートしました。 各gemのアップデートは次の手順で進めました。

  1. 変更履歴を確認し、破壊的な変更が入っていないか確認
  2. アップデートして、Rspecをすべてパスさせる
  3. ステージングにデプロイして動作確認
  4. 問題なければ本番環境に適用。

ほとんどコードの変更無しでアップデートできましたが、uglifier を 1.3.0 -> 4.1.202 にアップデートしたら次のエラーでプリコンパイルできなくなりました。

Uglifier::Error: Unexpected token: keyword (const). To use ES6 syntax, harmony mode must be enabled with Uglifier.new(:harmony => true)

この対処として config/environments/production.rb で、次の様に変更しました3

#config.assets.js_compressor = :uglifier #変更前
config.assets.js_compressor = Uglifier.new(harmony: true) # 変更後

Webpackerのアップグレード

一番手間がかかったのはWebpackerでした。

Webpacker2.0.0 からのアップデートでしたが 3.0.0台に上げると設定ファイルがいろいろ変わってしまうので先送りしていました。

面倒とはいえ、ビルドの仕組みなのでJSとSASSがエラーなくトランスパイルできれば、その後の問題は少ないのではないかとも思っていました。 そして、アップデートするからには Webpack4Babel7 にしようとも決めました。

アップデート作業の時点で、Webpack4に対応予定の Webpacker4はまだ正式リリースされておらず4.0.0.pre.3が最新リリースでした。トランスパイルしたものの動作に問題がなければ、正式版でなくても構わないと割り切りました。 Webpacker3に一旦アップデートするステップも意味がないと思ったのでスキップしました。 ということで 2.0.0 → 4.0.0.pre.3 のアップデートです。

次の手順でアップデートを進めました。

  1. Webpackerに関わる設定ファイルを一旦全部捨る。
  2. Webpacker4bundle exec rails webpacker:install:vueで設定ファイル群を生成
    • 既存設定を変更していくより、Webpacker4の設定を変更したほうが効率的だろうと判断。
  3. 生成した設定に追加で必要な設定を足していく
    • 次に関する設定を追加 Pug, SASS, Workbox, splitChunks

PugとSASSはVueモジュールの中で使っています。以前は必要なNPMパッケージをインストールするだけで、設定しなくてもvue-loaderがよしなにやってくれた気がするのですが4、それぞれローダーの設定ファイルを追加して動くようにしました。

Workboxは組み込む際のインタフェースの変更に伴う修正はしましたが、設定内容そのものは既存の設定から変更なく組み込めました。

splitChunksの導入

Webpack4 では CommonsChunk が廃止され、splitChunks に変わりました。もともと、CommonsChunkを使っていたので、splitChunksに移行したいと思ったのですが、Webpacker4.0.0.pre.3では、まだ未サポートでした。

でも、ドキュメントには設定方法が記載されているしなーと思ったら、4.0.0.pre.3より進んでいる作業当時のmasterではすでに実装が含まれる様子。まあ、どうせ導入しようとしているのもpreリリース版だし、動けばいいのだ! とWebpacker4のバージョンをその時のmasterHEADに変更しsplitChunksも使えるようになりました。

bundle exec rails webpacker:install:vueがインストールするVue.jsも当時の最新版で、もともと使っていたバージョンより新しいことを途中まで失念していました。が、特に動作に問題なさそうだったので結果オーライでそのままとしました(Vue.js 2.3.4 -> 2.5.20, Vuex 2.3.1 -> 2.5.0のアップデートとりました)。

Railsのアップデート

さていよいよRails(5.1.2 → 5.2.2)のアップデートです。

永久保存版Railsアップデートガイド - pixiv insideを参考に、次の2つを拠り所に作業を進めました。

Rails 5.1.6.1までのアップデートはパッチバージョン以下のアップデートなので大きな影響はなかろうと思われたので次の2フェーズに分けました。

  • 第1フェーズ:Rails 5.1.2 -> 5.1.6.1
  • 第2フェーズ:Rails 5.1.6.1 -> 5.2.2

各フェーズとも、Railsのリリースバージョンを1つづつアップデートしては動作確認していきました。

第1フェーズ Rails 5.1.2 -> 5.1.6.1

Rails 5.1.5 にアップグレードしたところで、次のようなCapybaraのバージョン不整合が発生しました。

can't activate capybara (~> 2.13), already activated capybara-3.12.0. Make sure all dependencies are added to Gemfile. System test integration requires Rails >= 5.1 and has a hard dependency on a webserver and capybara, please add capybara to your Gemfile and configure a webserver (e.g. Capybara.server = :webrick) before attempting to use system tests.

調べると、RailsのコードでCapybaraのバージョンを~> 2.13に指定してしまってました5

RSpecがFailするどころかはじまりもしないので困りました。Capybaraのバージョン下げる以外にどうにも対処法がなさそうなので、せっかく3.12.0にアップでデートしたのに2.13に下げました。

これ以外は特に詰まるところなく Rails 5.1.6.1 までアップデートできました。 第一フェーズではRails 5.1.6.1での動作確認後、すぐに本番適用しました。

第2フェーズ Rails 5.1.6.1 -> 5.2.2

Railsのアップデート自体では特に詰まるところなくアップデートできました。

Rails 5.2で導入されたいくつかの機能がありますが、次の様に対処しました。

  • Active Storage: 見送り
    • ディスコンと言いながらセキュリティアップデートやAWS SDKの変更への対応など必要なメンテナンスは続いているためPaperClipの利用を継続
  • HTTP/2 Early Hints:見送り
    • 導入したかったのですが、AWS ALBがサポートしていないので。
  • Content Security Policy:ちょっと先送り
    • すでに導入済みのネットワーク広告への影響を検証してから導入予定
  • Credentials:導入済
    • あとあと変更するのは面倒だっったので encrypted secrets から移行

まあ、保守的ですが、上記のとおりです。

Credentials は encrypted secretsと違って Rails.env で値を切り替える仕組みがないのがちょっと不便ですね。

リリース

Rails 5.2.2へのアップグレードのリリースに際しては、予期せぬエラーが発生すればすぐに戻せるよう次のような手順で実施しました。

  1. 旧環境を複製して新環境を作る
  2. 新旧の環境へのトラフィックをRoute53Weighted Routingを利用して振り分けられる様に設定する
  3. トラフィックを徐々に旧環境から新環境に移動させる。

いこレポは Elastic Beanstalkを利用しています。なので、旧環境を複製してもう1つ同じ環境を作るのは、数クリック、5,6分の作業です。

Route53Weighted Routingを設定したら、ClouwdWatchでエラーの発生を監視しつつ新環境の重みを増やしつつ、旧環境の重みを増やしていきました。もしもエラーが想定以上に発生すればすぐに旧環境に戻すことができます6

今回の場合、エラーは発生しなかったのでスムーズに新環境に移行できました。

最後に

アクトインディでは既存サービスもしっかりメンテしながら日々開発を進めています。 一緒に開発してくれるエンジニアを募集しています。


  1. 次の警告が出ていました。

  2. だいぶサボっておりました。

  3. https://github.com/lautis/uglifier/issues/127

  4. うろ覚えです。

  5. https://github.com/rails/rails/blob/0ae59ea828ed20141af0d4c9ed9130eb47ce55f3/actionpack/lib/action_dispatch/system_test_case.rb#L1

  6. 実際にはWeighted RoutingのTTL=60secのタイムラグは発生します。