こんにちは、エンジニアの森田です🌴
rails 5.2.0が発表されたのが2018年4月10日🚃
Rails 5.2.0 final is out the door! Just in time for @railsconf❤️. Please enjoy Active Storage, Redis Cache Store, HTTP/2 Early Hints, CSP, Credentials, and more! https://t.co/z4VWJTclhc
— DHH (@dhh) 2018年4月9日
大分遅くなってしまいましたが、2018年10月18日にメドピアが運営する医師専用コミュニティサイト「MedPeer」を、rails 5.1.6からrails 5.2.0にアップグレードしていました🎊
今回は、アップグレードを行った手順や躓いた部分を今更感もありますが紹介いたします🙌
アップグレードまでの道のり
まずはバージョンアップまでに行ったことの概要を下記にまとめました。
- リリースノートとアップグレードガイドを読んで影響を確認
- Gemfileのrailsのversionを
5.2.0
に変更してbundle update
rails app:update
で設定周りを更新- テストを実行し、失敗したor警告が発生した箇所を修正
- 社内の検証環境にデプロイして、動作確認
- 本番デプロイ
- 振り返り会
それぞれについて、実際にやったことを紹介いたします🙇
リリースノートとアップグレードガイドを読んで影響を確認
まずはRails5.2の変更点を知るためにRailsGuideのアップグレードガイドとリリースノートを読みました👀 (私は英語があまり得意ではないので、日本語版もあって非常に助かりました・・・!)
アップグレードガイド
- 本家:https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
- 日本語訳:https://railsguides.jp/upgrading_ruby_on_rails.html
リリースノート
- 本家: https://guides.rubyonrails.org/5_2_release_notes.html
- 日本語訳:https://railsguides.jp/5_2_release_notes.html
Gemfileのrailsのversionを5.2.0
に変更してbundle update
月に1回bundle update
を行っていて、比較的依存Gemのバージョンが上がっている、またマイナーバージョンのアップデートということで影響も少なそうだったので、bundle update
で依存Gemを含めて、アップグレードを行いました。
※月1回のbundle updateの施策については、こちらから👀
rails app:update
で設定周りを更新
次にrails app:update
をとりあえず全てyes
で実施して、危なそうな部分を戻す対応を行いました。影響が大きそうだった差分だけ下記に記載しておきます👀
bin/rails
、bin/rake
でspringをロードしないような変更が入っていたので反映しませんでした。active_storage
、test_unit
関連の設定ファイル追加及び既存ファイルへの更新は、使用していないので反映しませんでした。config/application.rb
のconfig.load_defaults
を5.2
に変更しました。bootsnap
は開発環境のみで動くようにし、本番での使用は一旦様子見しました。
設定ファイル関係はわからないことも多かったのですが、技術顧問の前島さんにレビューしてもらえるので安心・・・🙏
テストを実行し、失敗した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'moduleAdminRoutingTestHelperclass<< self# Admin配下のpath名と、それに合致するcontroller名とaction名を取得defadmin_routes(actions) routes = routes(actions) routes.select { |route| route[:name].include?('admin') } endprivatedefroutes(actions) routes = Rails.application.routes.routes routes = routes.map { |route| prepare_route(route) if route.name }.compact routes.select { |route| actions.include?(route[:action]) } enddefprepare_route(route) { name: route.name, action: route.requirements[:action], controller: route.defaults[:controller] } endendendRSpec.describe '画面に正常に遷移できるか確認'doIGNORE_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 200endendend
社内の検証環境にデプロイして、動作確認
テストのある部分はテストを全て通し、ない部分については先述の仕組みで確認したあと、ディレクターさんにも協力して頂き、業務上クリティカルな箇所について手で検証しました。
今回はマイナーバージョンアップということで、普段使っている本番相当の検証環境にバージョンアップを反映して検証を行いました。
本番デプロイ
通常業務に影響がなさそうという検証が出来たので、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に関しては乗り遅れずにバージョンアップ出来るように今回の反省を生かしていければと思います!