RailsをHerokuで5.1.3から5.2.1にアップグレードしてheroku-18スタックに対応した

こんにちは、hachi8833です。オレオレRailsアプリを5.1.3から5.2.1に、Rubyを最新の2.5.3にアップグレードしました。

環境

  • macOS: Mojave
  • Homebrewでrbenvをインストール
    • ただしruby-buildは ~/.rbenv/plugins/ruby-buildgit cloneで取得している
  • rbenvでRuby環境を構築している
  • bundlerを使ってプロジェクトディレクトリのvendor/ディレクトリにgemを置いている
  • デプロイ先: Heroku(ステージングと本番)

1. Rubyのアップグレード

まずはRubyのアップグレードから。2.5.0を最新の2.5.3にアップグレードします。

cd ~/.rbenv/plugins/ruby-build
git pull
rbenv install 2.5.3

次はRailsのRubyを2.5.3にアップグレードします。

  • Gemfileを更新します。
# Gemfile
-ruby '2.5.0'
+ruby '2.5.3'
  • 以下を実行してvendorディレクトリのgemを更新します。
bundle install

bundle exec rails sで動作を確認します。オレオレアプリは動的なページが1つしかないのでテストを回す意味がほぼありませんが、皆さんは必ずテストを回してください。

Herokuのステージングにデプロイして動作を確認できました。

git push enno-hachi-stg master

Railsのアップグレード

Rails アップグレードガイドの更新情報をみっちり読んでおきます。オレオレアプリに影響するところはなさそうでした。

  • Gemfileを更新します。
# Gemfile
-gem 'rails', '5.1.3'
+gem 'rails', '5.2.1'

アップグレードガイドに従い、bundle exec rails app:updateを実行します。

何もなければこれでおしまいです。いつもはだいたいこんなものです。

参考: Rails アップグレードガイド | Rails ガイド

Railsアップグレードのトラブルシューティング

しかしこんな恥ずかしいほどちっぽけなRailsアプリですら、今回はエラーメッセージが表示されます。

$ bundle exec rails app:update
Fetching gem metadata from https://rubygems.org/..........
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies....
Bundler could not find compatible versions for gem "activemodel":
  In snapshot (Gemfile.lock):
    activemodel (= 5.1.3)

  In Gemfile:
    kaminari was resolved to 1.0.1, which depends on
      kaminari-activerecord (= 1.0.1) was resolved to 1.0.1, which depends on
        activerecord was resolved to 5.1.3, which depends on
          activemodel (= 5.1.3)

    rails (= 5.2.1) was resolved to 5.2.1, which depends on
      activemodel (= 5.2.1)

Running `bundle update` will rebuild your snapshot from scratch, using only
the gems in your Gemfile, which may resolve the conflict.

まずはkaminariを単独でアップデートします。bundle update kaminariを実行します。

しかしメッセージはまったく同じでした。

そこでちょっと考えてからbundle updateを試してみました。ただしgem名を指定しないbundle updateは諸刃の剣。アップデートしてはまずいgemも含め全部を一気にアップデートするので、逆に事態をこじらせてしまう可能性もあります(↓以下の記事を参照)。オレオレアプリだからできることなので、業務アプリではこんな雑なことは絶対しないようにしましょう。

ちょっと待った! Railsでgitリポジトリから除外すべきでないファイル:Gemfile.lockとdb/schema.rb

どきどきしながらbundle updateし、bundle exec rails sしてみると、上のメッセージは解消しました。

factory_girlをfactory_botに変更

今度は以下です。ご存知のとおりfactory_girlはfactory_botに名前が変わったのですが、オレオレアプリではまだfactory_girlのままでした。

DEPRECATION WARNING: The factory_girl gem is deprecated. Please upgrade to factory_bot. See https://github.com/thoughtbot/factory_bot/blob/v4.9.0/UPGRADE_FROM_FACTORY_GIRL.md for further instructions. (called from require at /Users/hachi8833/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/bundler-1.16.6/lib/bundler/runtime.rb:81)

factory_girlをfactory_botに変更して再度bundle updateします(使ってないのでいっそ外してもいいくらいですが)。

案の定factory_girlがちょっぴりspecに残っていたのでfactory_botに更新しました。

FactoryBot.define do
  factory :mypattern, class: Pattern do
    regex 'ありがとうございません'
    # ruby_block {}
    comment '名作'
    posi_sample 'ありがとうございません'
    nega_sample 'ありがとうございます'
    # hit_count
    display_name '感謝'
    comment_e 'Fuck you very much'
    memorandom '世界遺産にしたい'
  end
end

私の場合あまり意味はないのですが、変更/削除に伴いbundle exec rspecを実行するとそこそこエラーが出ました。spec_helper.rbも修正が必要でした。

# spec_helper.rb

...
  config.before :all do
    FactoryGirl.reload   # FactoryBotに変更する
  end

  config.include FactoryGirl::Syntax::Methods # FactoryBotに変更する

  # 以下のDatabaseCleaner関連は削除する

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, js: true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

  system('bundle exec rake db:seed')

  # my config
  config.include AuthHelper
end

bundle exec rspecすると今度は以下が出ました。factory_botの書式が変わったようです。このあたりは今度まとめて対応することにしました。

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

【翻訳】factory_bot 4.11で非推奨になった静的属性(static attributes) - Qiita

不要なgemを削除

今度はrails_best_practicesが駄々をこねました。

/Users/hachi8833/deve/rails/enno/enno_master/vendor/bundle/ruby/2.5.0/gems/require_all-2.0.0/lib/require_all.rb:102:in `rescue in block in require_all': Could not require /Users/hachi8833/deve/rails/enno/enno_master/vendor/bundle/ruby/2.5.0/gems/rails_best_practices-1.18.1/lib/rails_best_practices/core/controllers.rb (uninitialized constant RailsBestPractices::Core::Klasses). Please require the necessary files (RequireAll::LoadError)

私の場合rails_best_practicesを直す意味がなかったので、この機会にgemを見直すことにしました。

  • 使ってないので削除
    • rails_best_practices
    • sdoc
    • derailed_benchmarks
    • yard
    • listen
  • Rails 5に同じ機能があるので削除
    • awesome_print
    • launchy
    • database_cleaner
    • capybara-screenshot

gem見直しの際は以下を参考にしました。

[Rails 5]実は不要なgem・使われなくなりつつあるgem(2017年版)

Webサーバーを修正

さらに、development/testのWebサーバーがPumaなのに、productionがunicornだということに今頃気づいたのでPumaに統一しました。環境ごとにWebサーバーを変える意味まったくなし、お恥ずかしい。

+gem 'puma'
...

group :production do
- gem 'unicorn'
  gem 'rails_12factor', '0.0.3' #Just for Heroku
  gem 'google-analytics-rails'
end

JavaScript/CSSの応急処置

Gemfileのgemを削除/更新してからbundle update後、bundle exec rails sすると起動しました。以下のwarningが出ました。

autoprefixer: /Users/hachi8833/deve/rails/enno/enno_master/app/assets/stylesheets/introjs.css:11:3: Gradient has outdated direction syntax. Replace `cover` to `farthest-corner`.

仰せのとおりにintrojs.cssのcoverfarthest-cornerに変更しました。サードパーティのファイルを直接変更するなど普通ならしませんが、を全然使ってないのでまたの機会に削除することにしました。

  background: -moz-radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);
  background: -webkit-gradient(radial,center center,0px,center center,100%,color-stop(0%,rgba(0,0,0,0.4)),color-stop(100%,rgba(0,0,0,0.9)));
  background: -webkit-radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);
  background: -o-radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);
  background: -ms-radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);
  background: radial-gradient(center,ellipse farthest-corner,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);

再度bundle exec rails sでローカルで実行できるかどうか確認しました。

# bundle exec rails s
=> Booting Puma
=> Rails 5.2.1 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.0 (ruby 2.5.3-p105), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop

これで一応めでたしです。

bootstrap-sassはまだsass-railsに依存している

しかしさっきupdate:appしたときに以下のメッセージが出ていました。

Ruby Sass is deprecated and will be unmaintained as of 26 March 2019.

* If you use Sass as a command-line tool, we recommend using Dart Sass, the new
  primary implementation: https://sass-lang.com/install

* If you use Sass as a plug-in for a Ruby web framework, we recommend using the
  sassc gem: https://github.com/sass/sassc-ruby#readme

* For more details, please refer to the Sass blog:
- gem 'sass-rails'
+ gem 'sassc'

しかし今度は以下のエラーです。

/Users/hachi8833/deve/rails/enno/enno_master/vendor/bundle/ruby/2.5.0/gems/bootstrap-sass-2.3.2.2/lib/bootstrap-sass.rb:14:in `require': cannot load such file -- sass-rails (LoadError)
enno_masterdevelopement8⬆1✔1✎ERROR$

bootstrap-sassのバージョンロックがいけないのかと思い、外してbundle updateしました。

-gem 'bootstrap-sass', '2.3.2.2'
-gem 'bootstrap-sass'

しかしうまくいきません。そもそもbootstrap-sassのgemspecにはsass-railsが指定されているので無理もありません。

bootstrap-sassはBootstrap 3向けですが、後発のBootstrap 4向け公式gemであるbootstrap-rubygemのgemspecをチェックすると、ちゃんとsasscが使われていました。使うならやはりこっちですね。

Bootstrap 4へのアップグレードはまたの機会とすることにします。

Herokuでのトラブル

しかしHerokuでstagingにデプロイすると、思いきりアプリケーションエラーになりました。さっきRubyのみをアップデートした時点では起きなかったのに…

どうやら以下のデプロイメッセージが原因のようです。

remote:  !   Warning: You are running on a deprecated stack.
remote:  !   Please upgrade to the latest stack by following the instructions on:
remote:  !   https://devcenter.heroku.com/articles/upgrading-to-the-latest-stack

Upgrading to the Latest Stack | Heroku Dev Centerを参照すると、以下の実行が必要なようです。

$ heroku stack:set heroku-18 -a <app name>

heroku-18って何?と思ったら以下の記事にありました。今は16ではなく18なんですね。

参考: Herokuの新しいスタック「Heroku-16」で何が変わったか? (2017年5月8日よりデフォルトに) - Qiita

$ heroku stack:set heroku-16 -a enno-hachi-stg

なお、Herokuのスタックはデプロイするまでは前のスタックが使われ続けます。

Webサーバーの変更: 続き

ここでherokuのダッシュボードを見ると、web
bundle exec unicorn -p $PORT -c ./config/unicorn.rb
となっているじゃありませんか。これをPumaに変えないとあかんようです。

Heroku側で変えるのかと思いきや、Railsプロジェクト直下のProcfileを書き換える必要がありました。

- web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
+ web: bundle exec puma -C config/puma.rb

これでDynoの起動コマンドも更新されました。

これで無事stagingで動きました!

後は本番デプロイです。以下を忘れず実行してスタックを更新してから、git push heroku masterを実行します。

$ heroku stack:set heroku-16 -a enno-hachi

本番デプロイも成功しました!

参考: Deploying Rails Applications with the Puma Web Server | Heroku Dev Center

関連記事

Ruby 2.5.2→2.5.3/2.4.5/2.3.8リリース(脆弱性修正)

ちょっと待った! Railsでgitリポジトリから除外すべきでないファイル:Gemfile.lockとdb/schema.rb

[Rails 5]実は不要なgem・使われなくなりつつあるgem(2017年版)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ