これは、度重なるエラーに苦戦しながらも初めての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.7.32 )
- Bundler ( 2.2.162 )
- Google Chrome.app( 91.0.4472.771 )
- Visual Studio Code.app( 1.56.21 )
本題
5. deviseとkaminariの各Gemを全環境で使えるようにする
なかなかそう簡単にはデプロイさせてくれない...
remote: !
remote: ! Precompiling assets failed.
remote: !
remote: ! Push rejected, failed to compile Ruby app.
remote:
remote: ! Push failed
出力されるエラーメッセージは多種多様だが、英単語を知ってれば自ずと読めるようになる。大事な部分は違う色などで強調して教えてくれるから、その付近を注視すれば成功したのか失敗したのかを把握する事は可能(但し、必ずしもそうとは限らないので注意)。上の6行だと、先頭3行が
remote: !
remote: ! Precompiling assets failed.
remote: !
というように、赤色で表示されていた。何だかよく分からんけど、「アセットのプリコンパイルに失敗した」から結果的にプッシュ(デプロイ)に失敗したと言っている事が分かる。ところで、この「プリコンパイル」とは一体何なのか?こちらのIT用語辞典では、
プリプロセッサとは、ソフトウェアの役割による分類の一つで、ある中心的な処理を行うプログラムに対して、その前処理(preprocess)3を行うプログラムのこと。プログラミング言語のコンパイラの前処理を行うものが非常に有名。
と説明している。この通りなんだろうが、要はコンパイラがコンパイル4しやすいように、ちょっとソースコードを改変する作業のこと。
- 外部ファイルの読み込み
- 文字列の置換
- 条件分岐処理
などなど。大学でCやJavaを少し習ったけど、その時に起こしてたコンパイルエラーは、このプリコンパイルが正しく処理されたのを前提とした上で発生したものだったのだろうか...?だとしたら解決策も変わってくる筈だ。出力されたメッセージを上から注意して見ていくと、
remote: Bundle completed (25.86s)
remote: Cleaning up the bundler cache.
remote: -----> Installing node-v12.16.2-linux-x64
remote: -----> Detecting rake tasks
remote: -----> Preparing app for Rails asset pipeline
remote: Running: rake assets:precompile
remote: rake aborted!
remote: NameError: uninitialized constant Devise
(以下略)
エラーの発生箇所を発見!「Bundle completed」とあるから、Gemの読み込みは完了したっぽい。問題はその後に起きたようだ。ここで「NameError: uninitialized constant Devise」でググってみたら、見事に解決方法が記述されているこちらの方の記事を見つけた。どうやら本番環境でGemが使えるように設定されてなかったのが原因だったようだ。そんな馬鹿な...と思ってGemfileを見てみたら、group :development, :test do ... end
の中にしっかりとセットしてますた(笑)早速devise
と、ついでにページネーション5実装時に使用するkaminari
もこのグループから取り出して、ファイルの最下部に書き直した。
(省略)
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'pry-rails'
gem 'compass-rails', '3.1.0'
gem 'sprockets', '3.7.2'
- gem 'devise'
- gem 'kaminari'
gem 'rspec-rails'
gem 'rails-controller-testing'
gem 'factory_bot_rails'
gem 'faker', '~> 2.8'
end
(省略)
# Use jquery as the JavaScript library
gem 'jquery-rails'
# 最下部に追加
+ gem 'devise'
+ gem 'kaminari'
**【別解】**若しくは下のように、開発・テスト・本番の3つの環境によるグループを作成してその中に入れ込む。
(省略)
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'pry-rails'
gem 'compass-rails', '3.1.0'
gem 'sprockets', '3.7.2'
- gem 'devise'
- gem 'kaminari'
gem 'rspec-rails'
gem 'rails-controller-testing'
gem 'factory_bot_rails'
gem 'faker', '~> 2.8'
end
(省略)
group :production do
gem 'rails_12factor'
end
# 全運用環境によるグループを作成
+ group :development, :test, :production do
+ gem 'devise'
+ gem 'kaminari'
+ end
(省略)
そりゃプリコンパイルできない訳だ...まぁ当時は本番環境のことを何も考慮してなかったから仕方ない...orz
因みに「NameError: uninitialized constant Devise」というエラーを見て、「Devise」が最初Gemのdevise
のことだと思わず、電子デバイスかなんかと勘違いしちゃって「ハードの問題か!?」とちょっと焦っちまったのは内緒...❤️
6. テンプレートリテラル記法を認識させる
さぁ、今回も楽しいたのしいデプロイチャレンジの時間がやって参りました!(白目)
ログインしてなかったらログインする
% heroku login --interactive
コードの全修正をインデックスに追加
% git add .
Let's commit!
% git commit -m “コミットメッセージ”
デプロイリベンジ
% git push heroku master
結果は...?
remote: !
remote: ! Precompiling assets failed.
remote: !
remote: ! Push rejected, failed to compile Ruby app.
remote:
remote: ! Push failed
ぐぬぬ...同じエラーか...しかし、メッセージを遡って読んでみると
remote: rake aborted!
remote: Uglifier::Error: Unexpected character '`'
(以下略)
良かった...少しは進展があったようだ。「予期してない文字『`』」というUglifier6によるエラー。
この解決策もこちらの方の記事に一緒に記述されてあった。このバッククオート`
は無論テンプレートリテラルによるものである。この記法を認識させるには、
(省略)
# Compress JavaScripts and CSS.
- config.assets.js_compressor = :uglifier
+ # config.assets.js_compressor = :uglifier ←この行をコメントアウト
# config.assets.css_compressor = :sass
(省略)
これだけでOK。
7. Gemのcompass-railsを無効にするつもりだった(意味のない変更)
このstepは完全に誤りです。恥ずかしいので無視してもらってかまいませんが、変更部分は一応記述しておきます。
remote: !
remote: ! Precompiling assets failed.
remote: !
remote: ! Push rejected, failed to compile Ruby app.
remote:
remote: ! Push failed
はい、またまたプリコンパイル失敗...。めげずにstep.5やstep.6と同様に出力メッセージを辿ってみる。
remote: rake aborted!
remote: Sass::SyntaxError: File to import not found or unreadable: compass.
(以下略)
お次は「インポートするcompassファイルが見つからないか読み取れない」というSyntaxError(構文エラー)。なぜか「見つからないなら無効にして無かった事にすれば良いじゃん!」と安直に考えてしまい、
- @import "compass";
+ // @import "compass"; ←先頭の第1行をコメントアウト
/*
* "ほのか明朝" licensed under the IPA Font License Agreement v1.0
* http://fontfree.me/966(配布元のURL)
* http://ipafont.ipa.go.jp/(IPAフォントのURL)
* http://ipafont.ipa.go.jp/ipa_font_license_v1.html(IPAフォントライセンスv1.0のURL)
*/
(以下略)
てやっちゃった!(・ω < )使用するためにインストールした筈なのに...
8. step.7による変更を元に戻して、Gemのcompass-railsを全環境で使えるようにする
remote: rake aborted!
remote: Sass::SyntaxError: Undefined mixin 'transition-property'.
(以下略)
内容が変わってるから少しずつゴールには向かっているのだろうけど、いつになったらこの「Precompiling assets failed.」のエラーから抜け出せるのか...先程と同じくSassによるSyntaxErrorだが、今度は「定義されてないmixin『transition-property』」とのこと。
フロントエンド学習時に少し出てきたけど、ちょっとだけ復習...。変数は値を定義するものだが、このmixinとはスタイルを定義するものである。これを利用すれば、何度も同じスタイルを使い回す事ができる。例えばセレクタの.clearfix
はよく使われる可能性のあるスタイルなので、
@mixin clearfix() {
&:after {
clear: both;
display: block;
content: "";
}
}
みたいに事前に定義しておき、必要になったら@include
を用いて
@include clearfix();
とすれば毎回呼び出す事ができる。さてさて、そんじゃ今回のスタイルシートで、mixinのtransition-property
を呼び出している箇所を見てみるか...
(省略)
.transition {
@include transition-property(all);
@include transition-duration(0.2s);
@include transition-timing-function(linear);
}
(省略)
あったあった。どうやら他にもtransition-duration
やtransition-timing-function
というmixinも併せて定義して、ここで一緒に呼び出しているようだ。ではこれらのmixinを定義している箇所も見てみるか...あれ?無いぞ!?command + p
で検索しても見つからない。別ファイルに定義してある訳でもなさそうだ...どうやらこれはGemのcompass-railsが関係しているらしい。そもそもこの『compass』って何だろう?
ちょっとググってみると、CSSを効率的に作成できるように設計されたSass用のフレームワークとのこと。多数のmixinや関数がライブラリ化してあり、色んな機能を提供してくれる。ここで、VSCodeから検索のサイドバーを開いて、上の検索ボックスにtransition-property
と入力し、これと同じ記述がしてあるコードを含むファイルがあるかどうかを調べてみると、
(省略)
.animate {
-moz-transition-property: all;
-o-transition-property: all;
-webkit-transition-property: all;
transition-property: all;
-moz-transition-duration: 0.2s;
-o-transition-duration: 0.2s;
-webkit-transition-duration: 0.2s;
transition-duration: 0.2s;
-moz-transition-timing-function: ease-in;
-o-transition-timing-function: ease-in;
-webkit-transition-timing-function: ease-in;
transition-timing-function: ease-in;
}
(省略)
発見した!ベンダープレフィックス7が付いてるのもあれば、そのまま使えるのもあるっぽい。これらはstep.7でコメントアウトした@import "compass";
により、モジュールとして読み込む事ができる。と言うことは、やっぱりこれを無効化するのは間違いだったか...
このGemについて理解しようとすると、俗に言うHTML/CSSの沼にまたハマってしまうこと間違い無しなので(笑)、とにかくエラーの解決に集中。step.7で付け加えたコメントを外して、「ローカル環境では普通に使えてたんだから、リモートでも使えるようにすれば良いだけじゃないのか」という正しい解釈に至った。
- // @import "compass";
+ @import "compass"; ←先頭の第1行のコメントを外す
/*
* "ほのか明朝" licensed under the IPA Font License Agreement v1.0
* http://fontfree.me/966(配布元のURL)
* http://ipafont.ipa.go.jp/(IPAフォントのURL)
* http://ipafont.ipa.go.jp/ipa_font_license_v1.html(IPAフォントライセンスv1.0のURL)
*/
(以下略)
step.5と同様に、開発・テストの両環境のグループからcompass-rails
を取り出して、ファイルの最下部に書き直す。ついでにアセットパイプライン8というものを実装するためのsprockets
というGemも、一緒に外に出しとくか。多分、問題無いだろう...
(省略)
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'pry-rails'
- gem 'compass-rails', '3.1.0'
- gem 'sprockets', '3.7.2'
gem 'rspec-rails'
gem 'rails-controller-testing'
gem 'factory_bot_rails'
gem 'faker', '~> 2.8'
end
(省略)
# Use jquery as the JavaScript library
gem 'jquery-rails'
# 最下部に追加
+ gem 'compass-rails', '3.1.0'
+ gem 'sprockets', '3.7.2'
gem 'devise'
gem 'kaminari'
**【別解】**若しくは下のように、開発・テスト・本番の3つの環境によるグループの中に入れ込む。
(省略)
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'pry-rails'
- gem 'compass-rails', '3.1.0'
- gem 'sprockets', '3.7.2'
gem 'rspec-rails'
gem 'rails-controller-testing'
gem 'factory_bot_rails'
gem 'faker', '~> 2.8'
end
(省略)
group :production do
gem 'rails_12factor'
end
# 全運用環境によるグループを作成
group :development, :test, :production do
+ gem 'compass-rails', '3.1.0'
+ gem 'sprockets', '3.7.2'
gem 'devise'
gem 'kaminari'
end
(省略)
9. 感動のフィナーレ
それは、一番下の方に記されてあった...
remote: Verifying deploy... done.
で...できたー! 正直この流れだとまだ続きそうな感じだったが、ようやくこの闘いに終止符が打たれた。厳密に言うと、少しこの上の方に
remote: ###### WARNING:
remote:
remote: No Procfile detected, using the default web server.
remote: We recommend explicitly declaring how to boot your server process via a Procfile.
remote: https://devcenter.heroku.com/articles/ruby-default-web-server
と表示されてあるが、多分現段階だと無視しても問題無い警告メッセージだろう。
今回学んだこと
- デプロイに対して牧歌的すぎた。ちょっとナメてた。
- 環境構築時以外でも、バージョンや依存関係は常に意識しておく。
- 新しいGemをインストールする際は、どの環境で運用させるべきかを予め把握しておく必要がある。
- エラーログに目立つ色で強調表示してある部分は重要なメッセージが記されている。そうじゃない部分にも重要なメッセージが記されている。
- やっぱり英語は大事。
今回はこの程度の変更修正で済んだけど、下手したらもっと多くのエラーが出て、もっと時間を費やす羽目になっていたかもしれない。こんな形で備忘録として残しておいて、同じようなエラーが発生したら直ぐに対処できるようにしておきたい。
これをもって、初めてのHerokuデプロイが完了したことにする。
参考記事
- Herokuにデプロイをする時に詰まった箇所について - Qiita
- compassエラーからのー - 思ったこと
- Grunt
- プリプロセッサとは - IT用語辞典
- Compassの使い方 - 過去記事 - [SMART]
- Uglifier::Error: Unexpected character '`' 【Railsデプロイエラー】 - 箱のプログラミング日記。
- CSSとは - IT用語辞典
- アセットパイプライン - Railsガイド
関連投稿記事
-
逆に、メインの処理に対する後処理を行うものをポストプロセッサというらしい。これは、いわゆるインタプリタとかを指すのかな? ↩
-
プログラミング言語で書かれたソースコードを解釈して、そのソースコードを今度はコンピュータが解釈、且つ実行できるネイティブコード(若しくはバイトコード)に変換する翻訳作業のこと。 ↩
-
長い文章を複数のページに分割して、各ページへのリンクを並べアクセスしやすくする機能。Googleなんかの検索結果のページの下に表示されてるアレ。 ↩
-
Railsに標準で搭載されているJavaScript軽量化のライブラリのことらしい。これは英語の『醜くする』という意味の『uglify』が由来っぽい? ↩
-
CSSでプロパティや値を指定する際に、各ブラウザのメーカーさんが独自に拡張した機能を呼び出すために付けられる接頭辞のこと。 ↩
-
JavaScriptやCSSなどのアセットを最小化または圧縮化して連結するためのフレームワークのことらしい。 ↩