Herokuデプロイ奮闘記（前編）

これは、度重なるエラーに苦戦しながらも初めてのHerokuデプロイに成功した、ある一人の男の物語である。



# 結論(デプロイまでの過程)
1. Rubyの**3.0.1**をインストールしてバージョン変更。
2. 更にRubyの**2.7.3**をインストールしてもう一度バージョン変更。Bundlerの**2.2.17**をインストールしてこっちもバージョン変更。
3. 更にBundlerの**2.2.16**をインストールしてこっちももう一度バージョン変更(Heroku環境に合わせるため)。このバージョンで`bundle install`。
4. BundlerをPCの環境に合わせるために、コマンド`bundle lock --add-platform x86_64-linux`を実行。
5. **devise**と**kaminari**の各Gemを開発･テスト･本番の全ての環境で使えるようにする。
6. *config/environments/production.rb*の`config.assets.js_compressor = :uglifier`の行をコメントアウトして、テンプレートリテラルを認識させる。
7. *app/assets/stylesheets/style.scss*先頭の`@import compass;`をコメントアウト。
8. *app/assets/stylesheets/style.scss*先頭の`@import compass;`のコメントを外して(元に戻して)、Gemの**compass-rails**を開発･テスト･本番の全ての環境で使えるようにする。
9. デプロイ完了！！

※今回も長くなりそう(なった)なので、前半と後半に記事を分けて書きます。



# 前提条件
- macOS Catalina ( 10.15.7[^1] )
- Rails ( 5.2.6[^1] )
- Terminal.app ( 2.10[^1] )
- Ruby ( 2.5.1[^2] )
- Bundler ( 2.1.4[^2] )
- Google Chrome.app( 91.0.4472.77[^1] )

[^1]: ブログ執筆時のバージョン
[^2]: デプロイ前初期バージョン



# 本題

### 1. Rubyのバージョンを変更する
コマンド`git push heroku master`を実行してデプロイ終わったと思いきや...

```terminal.app
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:  !
```

これが最初のエラーだった。この下には更に

```terminal.app
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:  !     

(以下略)
```

とメッセージが続いている。このエラーの解決策は、
&emsp;1. Rubyを対応しているバージョンに合わせる。
&emsp;2. Herokuのstackを下げる。
の２パターンあるが、後者はセキュリティやパフォーマンスの面で悪影響を及ぼす可能性があるらしいので、今回は省略(一応、上記のいずれかのstackに合わせれば解決はできるようだ)。というか、そもそもこの**stack**とは何ぞや..？こちらの[日本語の公式サイト](https://devcenter.heroku.com/ja/articles/stack)によれば、

>スタック​は、Heroku によってキュレートおよび維持されているオペレーティングシステムイメージです。 スタックは通常、Ubuntu などの既存のオープンソースの Linux ディストリビューションに基づいています。Heroku のアプリケーションは特定のスタックを対象とし、​buildpack​ は、あるアプリのソースコードを、そのスタックと互換性がある実行可能パッケージに変換する役目を担っています。

と記述されているが、正直よく分からない...Heroku用のOSといったところか。
さて、Rubyのバージョンを変えなければいけないのだが、上記エラーメッセージに記載されている[URLページ](https://devcenter.heroku.com/articles/ruby-support#supported-runtimes)に飛ぶと、以下のように記述されている箇所がある。

>MRI[^3]:
>
- `2.6.7`, Rubygems: `3.0.3.1`
- `2.7.3`, Rubygems: `3.1.6`
- `3.0.1`, Rubygems: `3.2.15`

[^3]: **Matz' Ruby Implementation**の略。C言語ベースのRuby。まつもとゆきひろ氏によって開発されたもので、最も一般的な処理系らしい。

この左側の各バージョン値からいずれかを選べば良さそうだ。ここではとりあえずあまり深く考えずに、最も新しいRuby`3.0.1`をインストールすることにした。

```terminal.app
念の為にホームディレクトリに移動して作業する
% cd ~

インストール出来るRubyのバージョン一覧を確認
% rbenv install --list
```
それぞれの環境にもよるが、一度上を実行すると、`2.6.7`も`2.7.3`も`3.0.1`も全部一覧に無い事が分かった。こういう時は、**`ruby-build`を最新版にアップデートする必要がある**。

```terminal.app
ついでにHomebrewもアップデート
% brew update

ruby-buildをアップデート
% brew upgrade ruby-build

再度バージョン一覧を確認
% rbenv install --list
```
すると、今度は`2.6.7`と`2.7.3`と`3.0.1`が３つ共きちんと表示された。同時に初めの`rbenv install --list`を実行した時のバージョンが全て消え失せてしまったのが謎なのだが、何はともあれこれで`3.0.1`をインストールする事ができるようになった。Rubyのインストールは環境構築ぶりだから少しドキドキする...

```terminal.app
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`に変更する。

```diff:.ruby_version
- 2.5.1
+ 3.0.1
```

```diff:Gemfile
- ruby '2.5.1'
+ ruby '3.0.1'
```
最後に、`bundle install`[^4]し直せば終了。

[^4]: `bundle update`で*Gemfile.lock*を直接再生成する方法でも良いのだろうが、余計な問題が発生する恐れを避けるため主流？な方で実践。

```terminal.app
デプロイ対象アプリのあるディレクトリに戻る
% 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`をやってみた。すると...

```terminal.app
`initialize': wrong number of arguments (given 3, expected 2) (ArgumentError)
```
サーバーが起動しなかった。案の定、エラーが発生した。上は、そのメッセージの一部分である。
**ArgumentError**とはすなわち**引数エラー**。「引数の数が違う」という訳で、この下に対象となるファイルであろうパスがズラーッと羅列表示されたが、どこをどう直せば良いのかサッパリ分からない...ググってもなかなか解決策が見つからずに困惑していたところ、[或る一つの記事](https://zenn.dev/jnchito/articles/24e0bd7fd1045d#後方互換性を窓から投げ捨てるような大きな変化はないが、マニアックな仕様変更がちょこちょこある)に辿り着いた。詳細は不明だが、後方互換性に影響を及ぼすかもしれないとのこと。憶測ながらも「これが原因なんじゃないかなぁ..」と思い、Rubyのバージョンを下げることに決定。`2.7.3`をインストールする。その前に、念の為にバージョン`2.5.1`に戻して再度`rails s`してみた。ローカルサーバーは問題なく起動した。やはり、いきなり最新版にバージョンアップしたのが宜しくなかったか...
[step.1](https://qiita.com/tsutsumin_pro/items/b68ea5b4b16826a5286c#1-rubyのバージョンを変更する)の流れに沿って、`2.7.3`をインストールする。`bundle install`まで終わらせると、文頭に以下のようなメッセージが出力された。

```terminal.app
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のバージョンを変更する。

```terminal.app
念の為にホームディレクトリに移動して作業する
% 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`すると

```terminal.app
*** LOCAL GEMS ***

bundler (default: 2.1.4)
```
更に`bundler -v`してみても

```terminal.app
Bundler version 2.1.4
```
あれれ〜？変わってないぞぉ〜？？しかし、なのにも関わらず、直訳すると「`2.1.4`はもう古いやんけ！バージョンアップしましょうよ」なる上の警告メッセージが今回はなぜか消えてしまっていた。これは一体どういうことなのだろうか...？
それもそのはずである。`2.2.17`がインストールされた事になってないのに一度*Gemfile.lock*を削除した後に`bundle install`してしまえば、デフォルトの`2.1.4`として再生成されるのは至極当然。ではなぜホームディレクトリでインストールしたBundlerの`2.2.17`が適用されなかったのだろうか？(念の為とは一体...)
[こちらの記事](https://qiita.com/scivola/items/8176304c03a92aebdfe2#総括)によると、**「`2.7`系列のRubyだとBundler関連で謎の挙動を示す」**的なことが述べられているのだが、今回の原因は別のところにある気がしてならない。というか、単純にホームディレクトリで導入したBundlerのパスを対象ディレクトリへ通してないから適用できてないだけのような...その方法がよく分からないので、今回はこのディレクトリ上でもう一度`2.2.17`版をインストールして誤魔化す事にした。

```terminal.app
現行最新版が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環境に合わせるために再度変更する
ここまででようやく最初のエラーを解決できたので、コミット後にもう一度デプロイしてみる。

```terminal.app
ログインしてなかったらログインする
% heroku login --interactive

コードの全修正をインデックスに追加
% git add .

Let's commit！
% git commit -m “コミットメッセージ”

デプロイリベンジ
% git push heroku master 
```
今度はどうだ！...

```terminal.app
remote:  !     Failed to install gems via Bundler.
remote:  !
remote:  !     Push rejected, failed to compile Ruby app.
remote: 
remote:  !     Push failed
```
はい、またエラーでーす。がっかり...。しかし、このエラーは[こちらの方の記事](https://yumishin.com/heroku-push-error/#i)のおかげで、案外あっさりと解決できた。要は、**Heroku環境のBundlerとローカル環境のBundlerとのバージョンが合ってなかった**のである。出力メッセージの上の方に、

```terminal.app
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](https://qiita.com/tsutsumin_pro/items/b68ea5b4b16826a5286c#2-rubyのバージョンを再度変更しbundlerのバージョンも変更する)と基本的な流れは同じ。

```terminal.app
意味ないかもだけど、ホームディレクトリで再び作業。念のたｍ..
% 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
```
:warning: もしこの後も何らかの理由で*Gemfile.lock*を削除するような事があった場合、その度に上のように特定のバージョンを指定して`bundle install`しなければ、毎回インストールされている最新バージョンのBundlerで再生成してしまう。若しくは、指定したいバージョンよりも新しい番号のBundlerを`gem uninstall bundler`のコマンドでアンイストールしても良い。使わなければの話だが...

というか、[step.2](https://qiita.com/tsutsumin_pro/items/b68ea5b4b16826a5286c#2-rubyのバージョンを再度変更しbundlerのバージョンも変更する)で「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のバージョンを再度変更したので、ここで一旦コミットして三度目のデプロイを試みる。

```terminal.app
remote:  !     Failed to install gems via Bundler.
remote:  !
remote:  !     Push rejected, failed to compile Ruby app.
remote: 
remote:  !     Push failed
```
なん...だと...！？？！？三度目の正直はなかった。二度あることは三度あった...ってさっきと同じじゃん！？結局さっきのエラーは解決できていなかったようだ...(泣)どういうことだってばよ！？混乱しそうだったが、これも[こちらの方の記事の続編](https://yumishin.com/heroku-push-error-2/#i)で難なく解決できた！
解決への道筋は、上記のエラーメッセージの直前に記載されていた。

```terminal.app
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環境に合わせなさい」**と言っているのだ。そっかそっか。じゃあ合わせましょうか。

```terminal.app
ここは素直にエラーメッセージで提案されているコマンドをコピペ実行
% bundle lock --add-platform x86_64-linux

差分を確認
% git diff
```
上の２つを実行すると、*Gemfile.lock*のPLATFORMSの欄に『x86_64-linux』が新たに追加されている事が分かる。

```diff:Gemfile.lock
PLATFORMS
  x86_64-darwin-19
+ x86_64-linux        ←これが追加される
```
:warning: デフォルトのプラットフォームが『x86_64-darwin-19』に設定されているようなので、これも再度*Gemfile.lock*を削除した後に`bundle install`してしまえば、この『x86_64-linux』の行が消えてデプロイできなくなる。そのため毎回`bundle lock --add-platform x86_64-linux`のコマンドを実行して、このプラットフォームを追加してあげなければならない。

因みに以前のBundler`2.1.4`だとこのPLATFORMSの箇所が『ruby』となっていたので、よく分からんけど、多分OSの環境に依存しない形でGemを管理していたんじゃないのかな(適当)
あとこれやっとけば[step.3](https://qiita.com/tsutsumin_pro/items/b68ea5b4b16826a5286c#3-bundlerのバージョンをheroku環境に合わせるために再度変更する)の手順は省略できたかもしれないけれど、ローカルとリモートとのバージョン値は合わせておいた方が無難だろう。
<br>
さて、ここまで色々変更してきたんだから、もうさすがにデプロイできるだろうなぁ〜✨(大きな期待)
もっかい試してみるか・・・

```terminal.app
remote:  !     Precompiling assets failed.
remote:  !
remote:  !     Push rejected, failed to compile Ruby app.
remote: 
remote:  !     Push failed
```
ギエピィィィィィィィィィィィィィィィィィィィ！！
ほわぁい！？ヘロクデベロップメントぴーぽー！！(泣)

この闘いが終わるのは、もう少し先のことであった...(後半へ続く)



# 参考記事
- [Heroku Ruby Support | Heroku Dev Center](https://devcenter.heroku.com/articles/ruby-support)
- [Stacks | Heroku Dev Center](https://devcenter.heroku.com/articles/stack)
- [【解決】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](https://qiita.com/___xxx_/items/12c8ab953bc6aaeb8c24)
- [サンプルコードでわかる！Ruby 3.0の主な新機能と変更点 Part 2 - 新機能と変更点の総まとめ](https://zenn.dev/jnchito/articles/24e0bd7fd1045d)
- [Bundler が Ruby 2.7 で変な件 - Qiita](https://qiita.com/scivola/items/8176304c03a92aebdfe2)
- [HerokuへPushする際に「Failed to install gems via Bundler.」が出た時の対処法](https://yumishin.com/heroku-push-error/)
- [Rubyアソシエーション: Ruby処理系の概要](https://www.ruby.or.jp/ja/tech/install/ruby/implementations.html)



# 次回予告
[Herokuデプロイ奮闘記（後編）](https://qiita.com/tsutsumin_pro/items/0db58f1439bffc17b327)