これは、度重なるエラーに苦戦しながらも初めてのHerokuデプロイに成功した、ある一人の男の物語である。
結論(デプロイまでの過程)
- Rubyの3.0.1をインストールしてバージョン変更。
- 更にRubyの2.7.3をインストールしてもう一度バージョン変更。Bundlerの2.2.17をインストールしてこっちもバージョン変更。
- 更にBundlerの2.2.16をインストールしてこっちももう一度バージョン変更(Heroku環境に合わせるため)。このバージョンで
bundle install
。 - BundlerをPCの環境に合わせるために、コマンド
bundle lock --add-platform x86_64-linux
を実行。 - deviseとkaminariの各Gemを開発・テスト・本番の全ての環境で使えるようにする。
-
config/environments/production.rbの
config.assets.js_compressor = :uglifier
の行をコメントアウトして、テンプレートリテラルを認識させる。 -
app/assets/stylesheets/style.scss先頭の
@import compass;
をコメントアウト。 -
app/assets/stylesheets/style.scss先頭の
@import compass;
のコメントを外して(元に戻して)、Gemのcompass-railsを開発・テスト・本番の全ての環境で使えるようにする。 - デプロイ完了!!
※今回も長くなりそう(なった)なので、前半と後半に記事を分けて書きます。
前提条件
- macOS Catalina ( 10.15.71 )
- Rails ( 5.2.61 )
- Terminal.app ( 2.101 )
- Ruby ( 2.5.12 )
- Bundler ( 2.1.42 )
- Google Chrome.app( 91.0.4472.771 )
本題
1. Rubyのバージョンを変更する
コマンドgit push heroku master
を実行してデプロイ終わったと思いきや...
remote: !
remote: ! The Ruby version you are trying to install does not exist on this stack.
remote: !
remote: ! You are trying to install ruby-2.5.1 on heroku-20.
remote: !
これが最初のエラーだった。この下には更に
remote: ! Ruby ruby-2.5.1 is present on the following stacks:
remote: !
remote: ! - cedar-14
remote: ! - heroku-16
remote: ! - heroku-18
remote: !
remote: ! Heroku recommends you use the latest supported Ruby version listed here:
remote: ! https://devcenter.heroku.com/articles/ruby-support#supported-runtimes
remote: !
(以下略)
とメッセージが続いている。このエラーの解決策は、
1. Rubyを対応しているバージョンに合わせる。
2. Herokuのstackを下げる。
の2パターンあるが、後者はセキュリティやパフォーマンスの面で悪影響を及ぼす可能性があるらしいので、今回は省略(一応、上記のいずれかのstackに合わせれば解決はできるようだ)。というか、そもそもこのstackとは何ぞや..?こちらの日本語の公式サイトによれば、
スタックは、Heroku によってキュレートおよび維持されているオペレーティングシステムイメージです。 スタックは通常、Ubuntu などの既存のオープンソースの Linux ディストリビューションに基づいています。Heroku のアプリケーションは特定のスタックを対象とし、buildpack は、あるアプリのソースコードを、そのスタックと互換性がある実行可能パッケージに変換する役目を担っています。
と記述されているが、正直よく分からない...Heroku用のOSといったところか。
さて、Rubyのバージョンを変えなければいけないのだが、上記エラーメッセージに記載されているURLページに飛ぶと、以下のように記述されている箇所がある。
MRI3:
-
2.6.7
, Rubygems:3.0.3.1
-
2.7.3
, Rubygems:3.1.6
-
3.0.1
, Rubygems:3.2.15
この左側の各バージョン値からいずれかを選べば良さそうだ。ここではとりあえずあまり深く考えずに、最も新しいRuby3.0.1
をインストールすることにした。
念の為にホームディレクトリに移動して作業する
% cd ~
インストール出来るRubyのバージョン一覧を確認
% rbenv install --list
それぞれの環境にもよるが、一度上を実行すると、2.6.7
も2.7.3
も3.0.1
も全部一覧に無い事が分かった。こういう時は、ruby-build
を最新版にアップデートする必要がある。
ついでにHomebrewもアップデート
% brew update
ruby-buildをアップデート
% brew upgrade ruby-build
再度バージョン一覧を確認
% rbenv install --list
すると、今度は2.6.7
と2.7.3
と3.0.1
が3つ共きちんと表示された。同時に初めのrbenv install --list
を実行した時のバージョンが全て消え失せてしまったのが謎なのだが、何はともあれこれで3.0.1
をインストールする事ができるようになった。Rubyのインストールは環境構築ぶりだから少しドキドキする...
Rubyの3.0.1をインストール
% rbenv install 3.0.1
リストの中に3.0.1があるのを確認
% rbenv versions
今回はRubyの3.0.1を全体で採用
% rbenv global 3.0.1
バージョンを切り替えたので変更を反映
% rbenv rehash
バージョンが3.0.1に切り替わっているのを確認
% ruby -v
次に、.ruby_versionとGemfileのRubyのバージョンも3.0.1
に変更する。
- 2.5.1
+ 3.0.1
- ruby '2.5.1'
+ ruby '3.0.1'
最後に、bundle install
4し直せば終了。
デプロイ対象アプリのあるディレクトリに戻る
% cd “アプリのディレクトリ”
Rubyの2.5.1で生成されていたGemfile.lockを一旦削除
% rm gemfile.lock
Gemfile.lockをRubyバージョン3.0.1で再生成
% bundle install
再生成されたGemfile.lockに記載されているRUBY VERSIONと一致しているのを確認
% ruby -v
2. Rubyのバージョンを再度変更し、Bundlerのバージョンも変更する
ここで僕は、ある一つの疑問を抱いた。「これでもしデプロイできたとしても、ローカルで動かせなかったら意味なくね??」。早速rails s
をやってみた。すると...
`initialize': wrong number of arguments (given 3, expected 2) (ArgumentError)
サーバーが起動しなかった。案の定、エラーが発生した。上は、そのメッセージの一部分である。
ArgumentErrorとはすなわち引数エラー。「引数の数が違う」という訳で、この下に対象となるファイルであろうパスがズラーッと羅列表示されたが、どこをどう直せば良いのかサッパリ分からない...ググってもなかなか解決策が見つからずに困惑していたところ、或る一つの記事に辿り着いた。詳細は不明だが、後方互換性に影響を及ぼすかもしれないとのこと。憶測ながらも「これが原因なんじゃないかなぁ..」と思い、Rubyのバージョンを下げることに決定。2.7.3
をインストールする。その前に、念の為にバージョン2.5.1
に戻して再度rails s
してみた。ローカルサーバーは問題なく起動した。やはり、いきなり最新版にバージョンアップしたのが宜しくなかったか...
step.1の流れに沿って、2.7.3
をインストールする。bundle install
まで終わらせると、文頭に以下のようなメッセージが出力された。
Warning: the running version of Bundler (2.1.4) is older than the version that created the lockfile (2.2.16). We suggest you to upgrade to the version that created the lockfile by running `gem install bundler:2.2.16`.
なるほど、Bundlerも更新させたほうが良さそうだ。その前に、もう一度このバージョンでrails s
を実行する。今回は上のような引数エラー等は一切発生せず、ちゃんとlocalhost:3000用のページもブラウザで表示された。まずは一安心...。
Rubyのバージョンは2.7.3
でいい感じなので、続いてBundlerのバージョンを変更する。
念の為にホームディレクトリに移動して作業する
% cd ~
最新のBundlerをインストールする
% gem update bundler
インストールされているバージョンの種類が増えているのを確認
% gem list bundler
現行最新版の2.2.17に切り替わっているのを確認
% bundler -v
デプロイ対象アプリのあるディレクトリに戻る
% cd “アプリのディレクトリ”
Bundlerの2.2.16で生成されていたGemfile.lockを一旦削除
% rm gemfile.lock
Gemfile.lockを再生成
% bundle install
ヨシ、これでうまくいった!...と思ったのも束の間、何だか様子がおかしい...カレントディレクトリでgem list bundler
すると
*** LOCAL GEMS ***
bundler (default: 2.1.4)
更にbundler -v
してみても
Bundler version 2.1.4
あれれ〜?変わってないぞぉ〜??しかし、なのにも関わらず、直訳すると「2.1.4
はもう古いやんけ!バージョンアップしましょうよ」なる上の警告メッセージが今回はなぜか消えてしまっていた。これは一体どういうことなのだろうか...?
それもそのはずである。2.2.17
がインストールされた事になってないのに一度Gemfile.lockを削除した後にbundle install
してしまえば、デフォルトの2.1.4
として再生成されるのは至極当然。ではなぜホームディレクトリでインストールしたBundlerの2.2.17
が適用されなかったのだろうか?(念の為とは一体...)
こちらの記事によると、**「2.7
系列のRubyだとBundler関連で謎の挙動を示す」**的なことが述べられているのだが、今回の原因は別のところにある気がしてならない。というか、単純にホームディレクトリで導入したBundlerのパスを対象ディレクトリへ通してないから適用できてないだけのような...その方法がよく分からないので、今回はこのディレクトリ上でもう一度2.2.17
版をインストールして誤魔化す事にした。
現行最新版が2.2.17である事が既に判明しているので、バージョン指定してアプリのディレクトリで再度インストール
% gem install bundler:2.2.17
インストールされているバージョンの種類が増えているのを確認
% gem list bundler
Bundlerの2.1.4で生成されていたGemfile.lockを一旦削除
% rm gemfile.lock
Gemfile.lockを再生成
% bundle install
再生成されたGemfile.lockに記載されているBUNDLED WITHと一致しているのを確認
% bundler -v
3. BundlerのバージョンをHeroku環境に合わせるために再度変更する
ここまででようやく最初のエラーを解決できたので、コミット後にもう一度デプロイしてみる。
ログインしてなかったらログインする
% heroku login --interactive
コードの全修正をインデックスに追加
% git add .
Let's commit!
% git commit -m “コミットメッセージ”
デプロイリベンジ
% git push heroku master
今度はどうだ!...
remote: ! Failed to install gems via Bundler.
remote: !
remote: ! Push rejected, failed to compile Ruby app.
remote:
remote: ! Push failed
はい、またエラーでーす。がっかり...。しかし、このエラーはこちらの方の記事のおかげで、案外あっさりと解決できた。要は、Heroku環境のBundlerとローカル環境のBundlerとのバージョンが合ってなかったのである。出力メッセージの上の方に、
remote: -----> Ruby app detected
remote: -----> Installing bundler 2.2.16
remote: -----> Removing BUNDLED WITH version in the Gemfile.lock
と記載されていたから、どうやら自分のHeroku環境ではバージョン2.2.16
のBundlerが使用されているようである。よって、ローカル環境のBundlerを改めてバージョン変更する。step.2と基本的な流れは同じ。
意味ないかもだけど、ホームディレクトリで再び作業。念のたm..
% cd ~
Bundlerの2.2.16をインストール
% gem install bundler:2.2.16
デプロイ対象アプリのあるディレクトリに戻る
% cd “アプリのディレクトリ”
同様にインストール
% gem install bundler:2.2.16
インストールされているバージョンの種類が増えているのを確認
% gem list bundler
Bundlerの2.2.17で生成されていたGemfile.lockを一旦削除
% rm gemfile.lock
Gemfile.lockをバージョン指定して再生成
% bundle _2.2.16_ install
再生成されたGemfile.lockに記載されているBUNDLED WITHと一致しているのを確認
% bundler -v
もしこの後も何らかの理由でGemfile.lockを削除するような事があった場合、その度に上のように特定のバージョンを指定してbundle install
しなければ、毎回インストールされている最新バージョンのBundlerで再生成してしまう。若しくは、指定したいバージョンよりも新しい番号のBundlerをgem uninstall bundler
のコマンドでアンイストールしても良い。使わなければの話だが...
というか、step.2で「We suggest you to upgrade to the version that created the lockfile by running gem install bundler:2.2.16
.(gem install bundler:2.2.16
でバージョンアップする事をオススメするよ)」の警告メッセージが出た時に、素直にこれやっとけば良かった...orz
4.BundlerのプラットフォームをPCの環境に合わせる
Bundlerのバージョンを再度変更したので、ここで一旦コミットして三度目のデプロイを試みる。
remote: ! Failed to install gems via Bundler.
remote: !
remote: ! Push rejected, failed to compile Ruby app.
remote:
remote: ! Push failed
なん...だと...!??!?三度目の正直はなかった。二度あることは三度あった...ってさっきと同じじゃん!?結局さっきのエラーは解決できていなかったようだ...(泣)どういうことだってばよ!?混乱しそうだったが、これもこちらの方の記事の続編で難なく解決できた!
解決への道筋は、上記のエラーメッセージの直前に記載されていた。
remote: Your bundle only supports platforms ["x86_64-darwin-19"] but your local platform
remote: is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote: --add-platform x86_64-linux` and try again.
remote: Bundler Output: Your bundle only supports platforms ["x86_64-darwin-19"] but your local platform
remote: is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote: --add-platform x86_64-linux` and try again.
1~3行目と4~6行目は同じことが書いてあるが、直訳すると「Bundlerのプラットフォームは["x86_64-darwin-19"]しかサポートしてないみたいだけど、あんたのローカル環境のプラットフォームは["x86_64-linux"]よ。bundle lock --add-platform x86_64-linux
でLOCKファイルに現在のプラットフォームを加えて、もっかい試してみな!」みたいになる。この「もっかい試して」とは「デプロイ」の事だろうが、問題の「x86_64-darwin-19」や「x86_64-linux」などは詳しくは知らないけどまぁザックリ言ってOSの事だろう。つまり、**「Bundlerをバージョンアップさせたんだったら自身のローカルPCのOS環境に合わせなさい」**と言っているのだ。そっかそっか。じゃあ合わせましょうか。
ここは素直にエラーメッセージで提案されているコマンドをコピペ実行
% bundle lock --add-platform x86_64-linux
差分を確認
% git diff
上の2つを実行すると、Gemfile.lockのPLATFORMSの欄に『x86_64-linux』が新たに追加されている事が分かる。
PLATFORMS
x86_64-darwin-19
+ x86_64-linux ←これが追加される
デフォルトのプラットフォームが『x86_64-darwin-19』に設定されているようなので、これも再度Gemfile.lockを削除した後にbundle install
してしまえば、この『x86_64-linux』の行が消えてデプロイできなくなる。そのため毎回bundle lock --add-platform x86_64-linux
のコマンドを実行して、このプラットフォームを追加してあげなければならない。
因みに以前のBundler2.1.4
だとこのPLATFORMSの箇所が『ruby』となっていたので、よく分からんけど、多分OSの環境に依存しない形でGemを管理していたんじゃないのかな(適当)
あとこれやっとけばstep.3の手順は省略できたかもしれないけれど、ローカルとリモートとのバージョン値は合わせておいた方が無難だろう。
さて、ここまで色々変更してきたんだから、もうさすがにデプロイできるだろうなぁ〜✨(大きな期待)
もっかい試してみるか・・・
remote: ! Precompiling assets failed.
remote: !
remote: ! Push rejected, failed to compile Ruby app.
remote:
remote: ! Push failed
ギエピィィィィィィィィィィィィィィィィィィィ!!
ほわぁい!?ヘロクデベロップメントぴーぽー!!(泣)
この闘いが終わるのは、もう少し先のことであった...(後半へ続く)
参考記事
- Heroku Ruby Support | Heroku Dev Center
- Stacks | Heroku Dev Center
- 【解決】heroku-20 You are trying to install ruby-2.6.5 on heroku-20. The Ruby version you are trying to install does not exist on this stack. - Qiita
- サンプルコードでわかる!Ruby 3.0の主な新機能と変更点 Part 2 - 新機能と変更点の総まとめ
- Bundler が Ruby 2.7 で変な件 - Qiita
- HerokuへPushする際に「Failed to install gems via Bundler.」が出た時の対処法
- Rubyアソシエーション: Ruby処理系の概要