【Rails/Heroku】Precompiling assets failed. への対処【プログラミング学習170日目】

# はじめに
個人用の備忘録です。

Herokuにデプロイした際に、`Precompiling assets failed.`というエラーでハマったのでその解決方法を残しておきたいと思います。

※注意事項として、試行錯誤しながらやっと解決できた感じなので、決してスマートな解決方法ではないと思います。その点はご了承ください。そしてこうしたらスマートに解決できるよ！というご意見がございましたら是非コメントいただければ幸いです！

# 前提
- 画像アップロード用のgemとして[Shrine](https://shrinerb.com/)を用いています。
 - 参考：[【Rails】Shrineの使い方【プログラミング学習156日目】](https://qiita.com/fuku_tech/items/abbce671e7d882ec2f14)

# 開発環境
- Ruby 2.5.1
- Rails 5.2.2
- Shrine 2.14.0

# エラーの内容
Herokuへのデプロイで`remote:  !     Precompiling assets failed.`というエラーが出てデプロイが失敗してしまう。

# 解決するために試したこと

まず、`$ bin/rails assets:precompile`をすると`config/initializers/shrine.rb`中の以下の箇所でエラーが発生していると怒られました。

下記箇所は画像アップロード用のgemとして用いた[Shrine](https://shrinerb.com/)の設定部分であり、開発環境では問題なく動いていた部分です。

よって、コード自体に変なミスはないと考えられました。

```config/initializers/shrine.rb
 ・・・
 Shrine.storages = {
   cache: Shrine::Storage::S3.new(prefix: 'cache', **s3_options),
   store: Shrine::Storage::S3.new(prefix: 'store', **s3_options)
 }
 ・・・
```

これだけでは情報が少なく、対処が出来ないと思ったため、更に原因を究明するために、[Heroku の assets:precompile で エラーが起きたときの調査方法](https://mittsu-blog.com/how-to-cheack-heroku-assets-precompile-error)を参考にし、調査を進めました。

そこで、まずは開発環境でPrecompileするために、以下を実行しました。
そして、ここは問題ないことを確認しました。

```
$ RAILS_ENV=development bin/rails assets:precompile
```

次に、本番環境でPrecompileが上手く行くかどうかを確認するために以下を実行しましたが、本番環境のS3バケット情報が定義されてないですよ、と怒られました。

```
$ RAILS_ENV=production bin/rails assets:precompile
  ArgumentError: the :bucket option is nil
```

この結果から、本番環境にS3のバケット情報が与えていない可能性が考えられたため、以下を実行しバケット情報の有無を確認することにしました。

すると、予想通り何も情報が入っていないことが分かりました。

```
$ echo $S3_BUCKET
$ echo $S3_REGION
$ echo $S3_ACCESS_KEY_ID
$ echo $S3_SECRET_ACCESS_KEY
```

そこで、Herokuにバケットの情報を与えるために、以下のように`heroku config:set`コマンドでバケット情報を一通りセットしていきました。

```
$ heroku config:set S3_BUCKET=バケット名
$ heroku config:set S3_REGION=リージョン名
$ heroku config:set S3_ACCESS_KEY_ID=アクセスキー
$ heroku config:set S3_SECRET_ACCESS_KEY=シークレットキー

$ heroku config  # バケット情報が入ったか確認
```

`$ heroku config`ではバケット情報が問題なく入っていたのですが、一方で、前述の`$ echo $S3_BUCKET`のような形で確認するとまだバケット情報が入っていないことが分かりました。（ここはなぜかはよく分かっていません）

そこで、改めて以下のように情報を入れていきました。

```
$ S3_BUCKET=バケット名
$ S3_REGION=リージョン名
$ S3_ACCESS_KEY_ID=アクセスキー
$ S3_SECRET_ACCESS_KEY=シークレットキー
```

前述の`$ echo $S3_BUCKET`で確認すると、今度はバケット情報が入ったことが分かりました。

バケット情報が入ったので、改めて本番環境でPrecompileが上手く行くかどうかを確認するために以下を実行しましたが、本番環境のS3バケット情報が定義されてないですよ、とまた怒られてしまいました。

```
$ RAILS_ENV=production bin/rails assets:precompile
  ArgumentError: the :bucket option is nil
```

そこで、`$ export`コマンドにてエクスポートすることにしました。

```
$ export S3_BUCKET=バケット名
$ export S3_REGION=リージョン名
$ export S3_ACCESS_KEY_ID=アクセスキー
$ export S3_SECRET_ACCESS_KEY=シークレットキー
```

すると、ようやく`$ RAILS_ENV=production bin/rails assets:precompile`をしてもバケット情報についてのエラーが出なくなりました！

この後の記憶がやや曖昧なのですが、確かバケット情報についてのエラーは出なくなったものの、まだ他のエラーが続いてprecompileが失敗したため、エラーに従って本番環境用の設定ファイルに以下を追加しました。

```config/environments/production.rb
# $ bin/rails assets:precompile を有効にするため
config.assets.compile = true  # falseからtrueに変更

# JavaScriptのES6に対応させるため
config.assets.js_compressor = Uglifier.new(harmony: true)
```

以上で、`$ RAILS_ENV=production bin/rails assets:precompile`をしても`remote:  !     Precompiling assets failed.`というエラーは出なくなりました！

# まとめ
- Herokuにデプロイした際に発生した`Precompiling assets failed.`というエラーの解決方法についてまとめました。
- `$ echo`コマンドなど、環境変数の設定や表示に関するコマンドについての知見が得られました。
- 試行錯誤しながらやっと解決できた感じなので、決してスマートな解決方法ではないと思います。その点はご了承ください。

# 参考URL
- [Heroku の assets:precompile で エラーが起きたときの調査方法](https://mittsu-blog.com/how-to-cheack-heroku-assets-precompile-error)