メドピア開発者ブログ

集合知により医療を再発明しようと邁進しているヘルステックリーディングカンパニーのエンジニアブログです。PHPからRubyへ絶賛移行中!継続的にアウトプットを出し続けられるようにみんなでがんばりまっす!

MedPeerをrails 5.2へアップデートしてました!🎊

こんにちは、エンジニアの森田です🌴

rails 5.2.0が発表されたのが2018年4月10日🚃

大分遅くなってしまいましたが、2018年10月18日にメドピアが運営する医師専用コミュニティサイト「MedPeer」を、rails 5.1.6からrails 5.2.0にアップグレードしていました🎊

f:id:madogiwa0124:20190105151411p:plain

今回は、アップグレードを行った手順や躓いた部分を今更感もありますが紹介いたします🙌

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

まずはバージョンアップまでに行ったことの概要を下記にまとめました。

  1. リリースノートとアップグレードガイドを読んで影響を確認
  2. Gemfileのrailsのversionを5.2.0に変更してbundle update
  3. rails app:updateで設定周りを更新
  4. テストを実行し、失敗したor警告が発生した箇所を修正
  5. 社内の検証環境にデプロイして、動作確認
  6. 本番デプロイ
  7. 振り返り会

それぞれについて、実際にやったことを紹介いたします🙇

リリースノートとアップグレードガイドを読んで影響を確認

まずはRails5.2の変更点を知るためにRailsGuideのアップグレードガイドとリリースノートを読みました👀 (私は英語があまり得意ではないので、日本語版もあって非常に助かりました・・・!)

アップグレードガイド

リリースノート

Gemfileのrailsのversionを5.2.0に変更してbundle update

月に1回bundle updateを行っていて、比較的依存Gemのバージョンが上がっている、またマイナーバージョンのアップデートということで影響も少なそうだったので、bundle updateで依存Gemを含めて、アップグレードを行いました。

※月1回のbundle updateの施策については、こちらから👀

speakerdeck.com

rails app:updateで設定周りを更新

次にrails app:updateをとりあえず全てyesで実施して、危なそうな部分を戻す対応を行いました。影響が大きそうだった差分だけ下記に記載しておきます👀

  • bin/railsbin/rakeでspringをロードしないような変更が入っていたので反映しませんでした。
  • active_storagetest_unit関連の設定ファイル追加及び既存ファイルへの更新は、使用していないので反映しませんでした。
  • config/application.rbconfig.load_defaults5.2に変更しました。
  • bootsnapは開発環境のみで動くようにし、本番での使用は一旦様子見しました。

設定ファイル関係はわからないことも多かったのですが、技術顧問の前島さんにレビューしてもらえるので安心・・・🙏

f:id:madogiwa0124:20190105151558p:plain

テストを実行し、失敗したor警告が発生した箇所を修正

とりあえず全体でテストを走らせて落ちた箇所と警告が発生していた部分を修正しました👷
主な修正は下記のようなところでした。

Arelのexistsを使っていた箇所を修正

existsを使っている箇所でDEPRECATION WARNING: Delegating exists to arel is deprecated and will be removed in Rails 6.0.の警告が発生していたため、下記のようにEXISTSではなくNOT INを使って行うように修正しました。

# before
where(Expert.where('users.id = experts.user_id').exists.not)
# after
where.not(id: Expert.select(:user_id)) }

Dangerous query method対応

rails 5.2から下記のようにsqlをハードコーディングするとDangerous query methodの警告が発生するようになりました。

Post.order('RAND()')

MedPeerでは固定の文字列を渡している箇所でのみ発生していたので、Arel.sqlで対応しました。

Post.order(Arel.sql('RAND()'))

テストの無い管理画面に立ち向かう

今回railsのバージョンを上げると同時に管理画面で使っているadministrateというgemのバージョンも大きくあがりました。メドピアでは管理画面ではクリティカルな部分以外でテストコードを書いていません😥
全てを手作業で確認するのは大変なので、今回はRails.application.routesを使ってpathを生成し、各画面遷移時にステータスコード200が返却されることを検証することで、手動テスト前の最低限の品質保証、バージョンアップによるエラーの検知が出来るようにしました🙇

require 'rails_helper'
module AdminRoutingTestHelper
  class << self
    # Admin配下のpath名と、それに合致するcontroller名とaction名を取得
    def admin_routes(actions)
      routes = routes(actions)
      routes.select { |route| route[:name].include?('admin') }
    end

    private

    def routes(actions)
      routes = Rails.application.routes.routes
      routes = routes.map { |route| prepare_route(route) if route.name }.compact
      routes.select { |route| actions.include?(route[:action]) }
    end

    def prepare_route(route)
      { name: route.name, action: route.requirements[:action], controller: route.defaults[:controller] }
    end
  end
end

RSpec.describe '画面に正常に遷移できるか確認' do
  IGNORE_PATH = [
    # 自動テスト対象外のpathを記載 
  ].freeze

  # 前提データが必要な場合は自動テストを行うのが難しいので、一覧と新規に限定
  admin_routes = AdminRoutingTestHelper.admin_routes(['index', 'new'])
  # 対象外のpathを除外
  target_routes = admin_routes.select { |route| IGNORE_PATH.exclude?(route[:name]) }
  url_helper = Rails.application.routes.url_helpers

  # 対象のpathの件数分、遷移しステータスコード200が返ってくることを検証
  target_routes.each do |route|
    describe route[:name] do
      before do
        visit url_helper.url_for(host: Capybara.app_host, controller: route[:controller], action: route[:action])
      end
      it "#{route[:controller]} # #{route[:action]}" do
        expect(page.status_code).to eq 200
      end
    end
  end

社内の検証環境にデプロイして、動作確認

テストのある部分はテストを全て通し、ない部分については先述の仕組みで確認したあと、ディレクターさんにも協力して頂き、業務上クリティカルな箇所について手で検証しました。

今回はマイナーバージョンアップということで、普段使っている本番相当の検証環境にバージョンアップを反映して検証を行いました。

本番デプロイ

通常業務に影響がなさそうという検証が出来たので、2018年10月18日にバージョン対応をmasterブランチにマージし、本番環境にデプロイしました🎊

VersionUp振り返り会

最後にバージョンアップの際に行ったことを整理して、KPTで振り返りを行いました。以下が出てきた内容の抜粋です🙇

Keep

  • 管理画面のテストを最低限ではあるが、自動的に行うことが出来た。

Problem

  • Gemfileで過去に色々な経緯からバージョンが固定されているGemがあり、月1のbundle updateで1年半程更新していないものもあった。railsのバージョンアップによる依存関係の解消時に大きくバージョン上げる必要があったため、検証負荷が高くなってしまった。
  • バージョンアップ用の環境を用意しておらず通常開発と同じ環境でバージョンアップの検証も行っていたため、通常開発業務の検証の際にバージョンアップを切り戻すといった作業が必要でメンテナンス負荷が高く、現状の検証環境のrailsのバージョンを把握しづらかった。

Try

  • Gemfileを読み解く会を開催し、経緯を理解した上で外せるものはバージョン固定を外す。
  • GemfileのVersion固定は、bundle updateのタイミングで見直す等の仕組み化を行う。
  • VersionUpのときは専用の環境を用意する。

Gemfileに記載されているgemがどのように使われているのか、なぜバージョンが固定化されているのかなどを読み解く会をやるといった今後のアクションに繋げることが出てきて、バージョンアップをするだけでなく、その過程で感じた問題等も話せたので振り返りいいのでは?という気持ちになりました🙌

おわりに

大分乗り遅れた感はありますが、今回はMedPeerをrails 5.2にバージョンアップした話でした。 現在6.0に関しても色々と情報が公開されてますが、次回の6.0に関しては乗り遅れずにバージョンアップ出来るように今回の反省を生かしていければと思います!