LoginSignup
15
13

More than 5 years have passed since last update.

Rails4のProduction環境でのAsset Pipelineで躓いたので検証した

Last updated at Posted at 2016-01-27

Asset Pipelineでハマった

Railsでアプリケーションを開発していると、Asset周りに問題が生じてdevelopment環境ではうまくいくのにProduction環境ではうまくいかないことがあります。私はフォントファイルを含むフレームワーク(Onsen UI)でハマったので、なぜうまくいかなかったのか検証してみました。

ここではRailsでFont Awesomeを使うアプリケーションを作ってみたいと思います。(普通RailsでFont Awesomeを使うときはgemかCDNを使ってください)

環境は、OS X 10.11,Chrome 47,Rails 4.2.4

Assetを配置する

Font Awesomeをダウンロードして解凍しました。
スクリーンショット 2016-01-23 00.27.25.png

lessscssはいらなそうなので削除しました。

Font Awesomeを置く場所

Railsでは、Assetを配置する場所は以下のように3箇所あります。

  • /app/assets/
  • /lib/assets/
  • /vendor/assets/

/lib/assets/は自作のライブラリ、/vendor/assets/は外部のライブラリを置くみたいですね。

RailsでJavaScriptライブラリの配置に迷う
http://shin.hateblo.jp/entry/2013/01/20/164924

なのでvendor/assets/以下に配置しました。
スクリーンショット 2016-01-23 00.48.44.png

Asset Pipelineに組み込む

app/assets/stylesheet/application.css
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
 * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any styles
 * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
 * file per style scope.
 *
 *= require_tree .
 *= require_self
 *= require_tree ../../../vendor/assets/font-awesome-4.5.0/.
 */

require_treefont-awesome-4.5.0配下をディレクトリごとAsset Pipelineに追加します。

development環境で試す

適当にcontroller,viewを作成します。

hogeview.html.erb
<h1>Test</h1>
<i class="fa fa-fort-awesome"></i>

rails s でサーバーを立ち上げます。
スクリーンショット 2016-01-23 00.53.51.png

できました。このときfont-awesome-4.5.0/css/font-awesome.cssからfont-awesome-4.5.0/font/fontawesome-webfont.woff2を読み込んでいます。ブラウザはこのfontawesome-webfont.woff2に、http://localhost:3000/assets/fonts/fontawesome-webfont.woff2?v=4.5.0でアクセスしています。

Production環境で試す

Production環境でサーバーを立ち上げるときはいくつか初期設定をする必要があります。

secretを設定

rake secretでシークレットキーを生成します。
secret_key_baseはgitにcommitしたくないので環境変数で設定するのがいいらしいです。でも今回はローカルでテストするだけなので直接書いてしまうことにしました。

config/secrets.yml
development:
  secret_key_base: 1bd92e6851e6a8fd5a6b828644a4a2c33d955866d65e65b956d69fde30cc05aad84f410abdb9adcedc8524bc7c29bdd72abbc8edd0222ebeb964d4a05992d28e

test:
  secret_key_base: 19c7e9c5fb7cb68f4995c0fc571b33527036122ef92494634be1288dddf6b9f4d048975ea0ca761c640b009fe18c4d00fff3509dc666ce4b423c20d0c31ad943

production:
  secret_key_base: 5eabd1e39824217842cbfdd187baac88d1dc7efc0da865bdeabd2ce0a2bea03a79a0c548be9126f92e95911fc2dbc4f1152b307b41e5f5152bac4c0a1833a07c

serve_static_filesをtrueに

静的なAssetを配信するのでtrueにします。

config/environments/production.rb
  config.serve_static_files = true

フォントをprecompileの対象にする

以下の行を追加します。

config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( *.svg *.eot *.woff *.woff2 *.ttf )

これでpublic/にフォントファイルがdigest付きでコピーされるようになります。

Rails4 でフォントの precompile に関する問題の解決策
http://qiita.com/onjiro/items/809dbc3c61b1fa576b26

assetをprecompile

development環境では、ページにアクセスするときにAssetがコンパイルされますが、production環境ではAssetを予めコンパイルしておく必要があります。このときにdigestが付加されたり、複数のcssやscriptが1つのファイルにまとめられる処理がされます。これが原因でproduction環境でうまくいかないことがしばしば...

bash
rake assets:precompile

サーバーを立ち上げる

bash
rails s -e production

スクリーンショット 2016-01-23 01.04.03.png

はい、うまくいきませんでした。
スクリーンショット 2016-01-23 01.04.13.png
フォントのファイルが404吐いてますね。。。ちなみにブラウザはこれらのファイルにhttp://localhost:3000/fonts/fontawesome-webfont.woff2?v=4.5.0のようなURLでアクセスしようとしています。

fontawesome-webfont.woff2のURLの違い

ブラウザがアクセスするURLはdevelopment環境とproductionで異なっていました。

development
http://localhost:3000/assets/fonts/fontawesome-webfont.woff2?v=4.5.0
→OK!
production
http://localhost:3000/fonts/fontawesome-webfont.woff2?v=4.5.0
→NG!

なぜこの違いが生まれるのでしょうか。ここでfont-awesome.cssを見てみたいと思います。

vendor/assets/font-awesome-4.5.0/css/font-awesome.css
/*!
 *  Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome
 *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
 */
/* FONT PATH
 * -------------------------- */
@font-face {
  font-family: 'FontAwesome';
  src: url('../fonts/fontawesome-webfont.eot?v=4.5.0');
  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');
  font-weight: normal;
  font-style: normal;
}
.fa {
  display: inline-block;
  font: normal normal normal 14px/1 FontAwesome;
  font-size: inherit;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.
.
.
.

ご覧のように相対パスで外部のフォントファイルを読み込んでいます。development環境では問題なくフォントファイルを読み込めるのですが、production環境ではcssがapplication.cssにまとめられてしまうので、パスに問題が生じると考えられます。

それぞれの環境でfont-awesome.cssが含まれるcssのパスを見てみると、
development:
http://localhost:3000/assets/css/font-awesome.self-096a1cf4b422c9c89eb905af2ee7bff3a955fc2ceefa7c0047237a0dddb7ce84.css?body=1

production:
http://localhost:3000/assets/application-586178e847adcc8902faa9d49adfc88c6c2df004a6ba8571cc56e726159e6172.css

となっていました。

スクリーンショット 2016-01-23 01.41.53.png

フォントを読み込むには?

今の構成だと、ほしいフォントファイルには以下のURLでアクセスでます:
http://localhost:3000/assets/fonts/fontawesome-webfont-ff82aeed6b9bb6701696c84d1b223d2e682eb78c89117a438ce6cfea8c498995.woff2

パスも修正する必要がありますが、まずdigestをなんとかしましょう。

non-stupid-digest-assetsを使う

non-stupid-digest-assetsはdigestなしのassetも書き出してくれるgemです。
Gemfilegem 'non-stupid-digest-assets'を追加してbundle installを実行します。

次に、non_digest_assets.rbを作成します。

config/initializers/non_digest_assets.rb
NonStupidDigestAssets.whitelist += [/fonts\/.*/]

パスはpublic/assets/からの相対パスを指定しましょう。
これでhttp://localhost:3000/assets/fonts/fontawesome-webfont.woff2でフォントファイルを読み込めるようになりました。

次にパスの修正を行います。

方法1 publicにfontを保存

スクリーンショット 2016-01-27 18.15.16.png
このようにfontsディレクトリをコピーすればうまくいきます。Font Awesomeののファイルが分散してしまうのが難点です。

方法2 cssを書き換える

以下のようにパスを修正すればフォントファイルを読み込めるようになります。font-awesome.cssfont-awesome.min.cssがありますが、後者は削除しておきましょう。

vendor/assets/font-awesome-4.5.0/css/font-awesome.css
/*!
 *  Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome
 *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
 */
/* FONT PATH
 * -------------------------- */
@font-face {
  font-family: 'FontAwesome';
  src: url('fonts/fontawesome-webfont.eot?v=4.5.0');
  src: url('fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');
  font-weight: normal;
  font-style: normal;
}
.fa {
  display: inline-block;
  font: normal normal normal 14px/1 FontAwesome;
  font-size: inherit;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.
.
.
.

これでフォントを正常に読み込めるようになります。でも外部のライブラリに手を加えるのはなるべく避けたいところです。

Asset Pipelineを諦める

結局のところ全部public/に配置してしまうのが一番簡単だと思います。Asset Pipelineの恩恵は受けられなくなりますが。。。
スクリーンショット 2016-01-27 20.37.50.png
HTMLでfont-awesome.min.cssを読み込みます。

hogeview.html.erb
<link rel="stylesheet" href="font-awesome-4.5.0/css/font-awesome.min.css">
<h1>Test</h1>
<i class="fa fa-fort-awesome"></i>

まとめ

  • Asset PipelineではCSSとJSが一つのファイルにまとめられるので、CSSやJSから別ファイルを読み込んでいる場合、パスの問題が起きることがある。
  • 外部のAssetでAsset Pipeline周りでハマったときは、Asset Pipelineを諦めてpublic/に配置したほうがいいかもしれない。
15
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
13