本ガイドでは、アセットパイプライン (asset pipeline) について解説します。
このガイドの内容:
アセットパイプラインとは、JavaScriptやCSSのアセットを最小化 (minify: スペースや改行を詰めるなど) または圧縮して連結するためのフレームワークです。アセットパイプラインでは、CoffeeScriptやSASS、ERBなど他の言語で記述されたアセットを作成する機能を追加することもできます。 アセットパイプラインはアプリケーションのアセットを自動的に他のgemのアセットと結合できます。たとえば、jquery-railsにはRailsでAJAXを使えるようにするjquery.jsが含まれています。
アセットパイプラインはsprockets-railsgemによって実装され、デフォルトで有効になっています。アプリケーションの新規作成中にアセットパイプラインを無効にするには、--skip-sprockets
オプションを渡します。
rails new appname --skip-sprockets
Railsではsass-rails
、coffee-rails
、uglifier
gemが自動的にGemfileに追加されます。Sprocketsはアセット圧縮の際にこれらのgemを使用します。
gem 'sass-rails' gem 'uglifier' gem 'coffee-rails'
--skip-sprockets
オプションを使用すると、Railsでsass-rails
とuglifier
がGemfileに追加されなくなります。アセットパイプラインを後から有効にしたい場合は、これらのgemもGemfileに追加する必要があります。同様に、アプリケーション新規作成時に--skip-sprockets
オプションを指定するとconfig/application.rb
ファイルの記述内容がデフォルトから若干異なります。具体的にはsprocket railtieで必要となる記述がコメントアウトされます。アセットパイプラインを手動で有効にする場合は、これらのコメントアウトも解除する必要があります。
# require "sprockets/railtie"
アセット圧縮方式を指定するには、production.rb
の該当する設定オプションを設定します。config.assets.css_compressor
はCSSの圧縮方式、config.assets.js_compressor
はJavaScriptの圧縮方式をそれぞれ指定します。
config.assets.css_compressor = :yui config.assets.js_compressor = :uglifier
sass-rails
gemがGemfile
に含まれていれば自動的にCSS圧縮に使用されます。この場合config.assets.css_compressor
オプションは設定されません。
アセットパイプラインの第一の機能はアセットを連結することです。これにより、ブラウザがWebページをレンダリングするためのリクエスト数を減らすことができます。Webブラウザが同時に処理できるリクエスト数には限りがあるため、同時リクエスト数を減らすことができればその分読み込みが高速になります。
SprocketsはすべてのJavaScriptファイルを1つのマスター.js
ファイルに連結し、すべてのCSSファイルを1つのマスター.css
ファイルに連結します。本ガイドで後述するように、アセットファイルをグループ化する方法は自由にカスタマイズできます。production環境では、アセットファイル名にSHA256フィンガープリントを挿入し、アセットファイルがWebブラウザでキャッシュされるようにしています。このフィンガープリントを変更することでブラウザでキャッシュされていた既存のアセットを無効にすることができます。フィンガープリントの変更は、アセットファイルの内容が変更された時に自動的に行われます。
アセットパイプラインのもうひとつの機能はアセットの最小化 (一種の圧縮) です。CSSファイルの最小化は、ホワイトスペースとコメントを削除することによって行われます。JavaScriptの最小化プロセスはもう少し複雑です。最小化方法はビルトインのオプションから選んだり、独自に指定したりすることができます。
アセットパイプラインの第3の機能は、より高級な言語を使用したコーディングのサポートです。これらの言語で記述されたコードはプリコンパイルされ、実際のアセットになります。デフォルトでサポートされている言語は、CSSに代わるSASS、JavaScriptに代わるCoffeeScript、CSS/JavaScriptに代わるERBです。
アセットファイル名で使用されるフィンガープリントは、アセットファイルの内容に応じて変わります。アセットファイルの内容が少しでも変わると、アセットファイル名も必ずそれに応じて変わります (訳注: MD5の性質により、異なるファイルからたまたま同じフィンガープリントが生成されることはほぼありません)。変更されていないファイルやめったに変更されないファイルがある場合、フィンガープリントも変化しないので、ファイルの内容が完全に同一であることが容易に確認できます。これはサーバーやデプロイ日が異なっていても有効です。
アセットファイル名は内容が変わると必ず変化するので、CDN、ISP、ネットワーク機器、Webブラウザなどあらゆる場面で有効なキャッシュをHTTPヘッダに設定することができます。ファイルの内容が更新されると、フィンガープリントも更新されます。これにより、リモートクライアントは (訳注: 既存のキャッシュを使用せずに) コンテンツの新しいコピーをサーバーにリクエストします。この手法を一般に キャッシュ破棄 (cache busting) と呼びます。
Sprocketsがフィンガープリントを使用する際には、ファイルの内容をハッシュ化したものをファイル名 (通常は末尾) に追加します。たとえば、global.css
というCSSファイル名は以下のようになります。
global-908e25f4bf641868d8683022a5b62f54.css
これはRailsのアセットパイプラインの戦略として採用されています。
以前のRailsでは、ビルトインのヘルパーにリンクされているすべてのアセットに日付ベースのクエリ文字列を追加するという戦略が使用されていました。当時のソースで生成されたコードは以下のようになります。
/stylesheets/global.css?1309495796
このクエリ文字列ベースの戦略には多くの問題点があります。
クエリパラメータ以外にファイル名に違いのないコンテンツは確実にキャッシュされないことがある
Steve Soudersのブログ記事によると、「キャッシュされる可能性のあるリソースにクエリ文字列でアクセスするのは避けること」が推奨されています。Steveは、5%から20%ものリクエストがキャッシュされていないことに気付きました。クエリ文字列は、キャッシュ無効化が発生する一部のCDNでは役に立ちません。
マルチサーバー環境でファイル名が異なってしまうことがある
Rails 2.xのデフォルトのクエリ文字列はファイルの更新日付に基いていました。このアセットをサーバークラスタにデプロイすると、サーバー間でファイルのタイムスタンプが同じになる保証がないため、リクエストを受けるサーバーが変わるたびに値が異なってしまいます。
キャッシュの無効化が過剰に発生する
コードリリース時のデプロイが行われると、アセットに変更があるかどうかにかかわらず すべての ファイルのmtime (最後に更新された時刻) が変更されてしまいます。このため、アセットに変更がなくてもWebブラウザを含むあらゆるリモートクライアントで強制的にアセットが再取得されてしまいます。
フィンガープリントが導入されたことによって上述のクエリ文字列による問題点が解決され、アセットの内容が同じであればファイル名も常に同じになるようになりました。
フィンガープリントはdevelopment環境とproduction環境の両方でデフォルトでオンになります。設定ファイルでconfig.assets.digest
オプションを使用してフィンガープリントのオン/オフを制御できます。
詳細については以下を参照してください。
以前のRailsでは、すべてのアセットはpublic
ディレクトリの下のimages
、javascripts
、stylesheets
などのサブフォルダに置かれました。アセットパイプライン導入後は、app/assets
ディレクトリがアセットの置き場所として推奨されています。このディレクトリに置かれたファイルはSprocketsミドルウェアによってサポートされます。
アセットは引き続きpublic
ディレクトリ以下に置くことも可能です。config.public_file_server.enabled
がtrueに設定されていると、public
ディレクトリ以下に置かれているあらゆるアセットはアプリケーションまたはWebサーバーによって静的なファイルとして取り扱われます。プリプロセスが必要なファイルはapp/assets
ディレクトリの下に置く必要があります。
productionモードでは、Railsはプリコンパイルされたファイルをpublic/assets
に置きます。プリコンパイルされたファイルは、Webサーバーによって静的なアセットとして扱われます。app/assets
に置かれたファイルがそのままの形でproduction環境で使用されることは決してありません。
Railsでscaffoldやコントローラを生成すると、JavaScriptファイル (coffee-rails
gemがGemfile
で有効になっている場合はCoffeeScript) とCSS (sass-rails
gemがGemfile
で有効になっている場合はSCSS) もそのコントローラ用に生成されます。scaffold生成時には、さらにscaffolds.css
(sass-rails
gemがGemfile
で有効になっている場合はscaffolds.css.scss
) も生成されます。
たとえばProjectsController
を生成すると、app/assets/javascripts/projects.coffee
ファイルとapp/assets/stylesheets/projects.scss
ファイルが新しく作成されます。require_tree
ディレクティブを使用すると、これらのファイルを即座にアプリケーションから利用できます。require_treeの詳細についてはマニフェストファイルとディレクティブを参照してください。
関連するコントローラで以下のコードを使用することで、コントローラ固有のスタイルシートやJavaScriptファイルをそのコントローラだけで使用できます。
<%= javascript_include_tag params[:controller] %>
または <%= stylesheet_link_tag params[:controller] %>
上のコードを使用する際は、require_tree
ディレクティブを使用していないことを必ず確認してください。require_tree
と併用すると、アセットが2回以上インクルードされてしまいます。
アセットのプリコンパイルを使用する場合、ページが読み込まれるたびにコントローラのアセットがプリコンパイルされるようにしておく必要があります。デフォルトでは、.coffee
ファイルと.scss
ファイルは自動ではプリコンパイルされません。プリコンパイルの動作の詳細については、アセットをプリコンパイルするを参照してください。
CoffeeScriptを使用するには、ExecJSがランタイムでサポートされている必要があります。macOSまたはWindowsを使用している場合は、OSにJavaScriptランタイムをインストールしてください。サポートされているすべてのJavaScriptランタイムに関するドキュメントは、ExecJS で参照できます。
config/application.rb
設定に以下を追加することで、コントローラ固有のアセットファイル生成を止めることもできます。
config.generators do |g| g.assets false end
パイプラインのアセットは、アプリケーション内のapp/assets
、lib/assets
、vendor/assets
の3つのディレクトリのいずれかに置くことができます。
app/assets
は、カスタム画像ファイル、JavaScript、スタイルシートなど、アプリケーション自身が保有するアセットの置き場所です。
lib/assets
は、1つのアプリケーションの範疇に収まらないライブラリのコードや、複数のアプリケーションで共有されるライブラリのコードを置く場所です。
vendor/assets
は、JavaScriptプラグインやCSSフレームワークなど、外部の団体などによって所有されているアセットの置き場所です。
Rails 3からのアップグレードを行なう際には、lib/assets
とvendor/assets
の下に置かれているアセットがRails 4ではアプリケーションのマニフェストによってインクルードされて利用可能になること、しかしプリコンパイル配列の一部には含まれなくなることを考慮に入れてください。ガイダンスについてはアセットをプリコンパイルするを参照してください。
ファイルがマニフェストやヘルパーから参照される場合、Sprocketsはデフォルトのアセットの置き場所である3つのディレクトリからファイルを探します。
3つのディレクトリとは、app/assets
の下にあるimages
、javascripts
、stylesheets
ディレクトリです。ただしこれらのサブディレクトリは特殊なものではなく、実際にはassets/*
以下のすべてのパスが検索対象になります。
以下のファイルを例に説明します。
app/assets/javascripts/home.js lib/assets/javascripts/moovinator.js vendor/assets/javascripts/slider.js vendor/assets/somepackage/phonebox.js
上のファイルはマニフェスト内で以下のように参照されます。
//= require home //= require moovinator //= require slider //= require phonebox
サブディレクトリ内のアセットにもアクセスできます。
app/assets/javascripts/sub/something.js
上のファイルは以下のように参照されます。
//= require sub/something
検索パスを調べるには、RailsコンソールでRails.application.config.assets.paths
を調べます。
config/initializers/assets.rb
に記述することで、標準のassets/*
に加えて追加の (fully qualified) パスをパイプラインに追加することができます。以下の例で説明します。
Rails.application.config.assets.paths << Rails.root.join("lib", "videoplayer", "flash")
パスの探索は、検索パスでの出現順で行われます。デフォルトではapp/assets
の検索が優先されるので、対応するパスがlib
やvendor
にある場合はマスクされます。
ここでご注意いただきたいのは、参照したいファイルがマニフェストの外にある場合は、それらをプリコンパイル配列に追加しなければならないという点です。追加しない場合、production環境で利用することができなくなります。
Sprocketsでは、index
という名前のファイル (および関連する拡張子) を特殊な目的に使用します。
たとえば、たくさんのモジュールがあるjQueryライブラリを使用していて、それらがlib/assets/javascripts/library_name
に保存されているとします。このlib/assets/javascripts/library_name/index.js
ファイルはそのライブラリ内のすべてのファイルで利用できるマニフェストとして機能します。このファイルには必要なファイルをすべて順に記述するか、あるいは単にrequire_tree
と記述します。
一般に、このライブラリはアプリケーションマニフェストに以下のように記述することでアクセスできます。
//= require library_name
このように記述することで、他でインクルードする前に関連するコードをグループ化できるようになり、記述が簡潔になり保守がしやすくなります。
Sprocketsはアセットにアクセスするためのメソッドを特に追加しません。従来同様javascript_include_tag
とstylesheet_link_tag
を使用します。
<%= stylesheet_link_tag "application", media: "all" %> <%= javascript_include_tag "application" %>
Railsから同梱されるようになったturbolinks gemを使用している場合、'data-turbolinks-track'オプションが利用できます。これはアセットが更新されてページに読み込まれたかどうかをturbolinksがチェックします。
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => "reload" %> <%= javascript_include_tag "application", "data-turbolinks-track" => "reload" %>
通常のビューでは以下のような方法でapp/assets/images
ディレクトリの画像にアクセスできます。
<%= image_tag "rails.png" %>
パイプラインが有効でかつ現在の環境で無効になっていない場合、このファイルはSprocketsによって扱われます。ファイルがpublic/assets/rails.png
に置かれている場合、Webサーバーによって扱われます。
public/assets/rails-f90d8a84c707a8dc923fca1ca1895ae8ed0a09237f6992015fef1e11be77c023.png
など、ファイル名にSHA256ハッシュを含むファイルへのリクエストについても同様に扱われます。ハッシュの生成法については、本ガイドのproduction環境の場合で後述します。
Sprocketsはconfig.assets.paths
で指定したパスも探索します。このパスには、標準的なアプリケーションパスと、Railsエンジンによって追加されるすべてのパスが含まれます。
必要であれば画像ファイルをサブディレクトリに置いて整理することもできます。この画像にアクセスするには、ディレクトリ名を含めて以下のようにタグで指定します。
<%= image_tag "icons/rails.png" %>
アセットのプリコンパイルを行っている場合 (production環境の場合参照)、存在しないアセットへのリンクを含むページを呼び出すと例外が発生します。空文字へのリンクも同様に例外が発生します。ユーザーから提供されたデータに対してimage_tag
などのヘルパーを使用する場合はご注意ください。
アセットパイプラインは自動的にERBを評価します。たとえば、cssアセットファイルにerb
という拡張子を追加すると (application.css.erb
など)、CSSルール内でasset_path
などのヘルパーが使用できるようになります。
.class { background-image: url(<%= asset_path 'image.png' %>) }
これは、指定されたアセットへのパスを記述します。上の例では、アセット読み込みパスのいずれかにある画像ファイル (app/assets/images/image.png
など) が指定されたと解釈されます。この画像が既にフィンガープリント付きでpublic/assets
にあれば、このパスによる参照は有効になります。
データURIスキーム (CSSファイルにデータを直接埋め込む手法) を使用したい場合は、asset_data_uri
を使用できます。
#logo { background: url(<%= asset_data_uri 'logo.png' %>) }
上のコードは、CSSソースに正しくフォーマットされたdata URIを挿入します。
この場合、-%>
でタグを閉じることはできませんのでご注意ください。
アセットパイプラインを使用する場合、最終的にアセットへのパスを変換する必要があります。このために、sass-rails
gemは名前が-url
や-path
で終わる (Sass内ではハイフンですが、Rubyではアンダースコアで表します) 各種ヘルパーを提供しています。ヘルパーがサポートするアセットクラスは、画像、フォント、ビデオ、音声、JavaScript、stylesheetです。
image-url("rails.png")
はurl(/assets/rails.png)
に変換されるimage-path("rails.png")
は"/assets/rails.png"
に変換される以下のような、より一般的な記法を使用することもできます。
asset-url("rails.png")
はurl(/assets/rails.png)
に変換されるasset-path("rails.png")
は"/assets/rails.png"
に変換されるJavaScriptアセットにerb
拡張子を追加すると (application.js.erb
など)、以下のようにJavaScriptコード内でasset_path
ヘルパーを使用できます。
$('#logo').attr({ src: "<%= asset_path('logo.png') %>" });
これは、指定されたアセットへのパスを記述します。
CoffeeScriptファイルでも、application.coffee.erb
のようにerb
拡張子を追加することで同様にasset_path
ヘルパーを使用できます。
$('#logo').attr src: "<%= asset_path('logo.png') %>"
Sprocketsでは、どのアセットをインクルードしてサポートするかを指定するのにマニフェストファイルを使用します。マニフェストファイルには ディレクティブ (directive: 命令、指示) を含めます。ディレクティブを使用して必要なファイルを指定し、それに基いて最終的に単一のCSSやJavaScriptファイルがビルドされます。Sprocketsはディレクティブで指定されたファイルを読み込み、必要に応じて処理を行い、連結して単一のファイルを生成し、圧縮します (Rails.application.config.assets.compress
がtrueの場合)。ファイルを連結してひとつにすることにより、ブラウザからサーバーへのリクエスト数を減らすことができ、ページの読み込み時間が大きく短縮されます。圧縮することによってもファイルサイズが小さくなり、ブラウザへの読み込み時間が短縮されます。
新規作成したRailsアプリケーションにはデフォルトでapp/assets/javascripts/application.js
ファイルに以下のような記述が含まれています。
// ... //= require rails-ujs //= require turbolinks //= require_tree .
JavaScriptのSprocketsディレクティブは//=
で始まります。上の例ではrequire
とrequire_tree
というディレクティブが使用されています。require
は、必要なファイルをSprocketsに指定するのに使用します。ここではrails-ujs.js
とturbolinks.js
を必要なファイルとして指定しています。これらのファイルはSprocketsの検索パスのどこかから読み込み可能になっています。このディレクティブでは拡張子を明示的に指定する必要はありません。ディレクティブが.js
ファイルに書かれていれば、Sprocketsによって自動的に.js
ファイルが必要ファイルとして指定されます。
require_tree
ディレクティブは、指定されたディレクトリ以下の すべての JavaScriptファイルを再帰的にインクルードし、出力に含めます。このパスは、マニフェストファイルからの相対パスとして指定する必要があります。require_directory
ディレクティブを使用すると、指定されたディレクトリの直下にあるすべてのJavaScriptファイルのみをインクルードします。この場合サブディレクトリを再帰的に探索しません。
ディレクティブは記載した順に実行されますが、require_tree
でインクルードされるファイルの読み込み順序は指定できません。従って、特定の読み込み順に依存しないようにする必要があります。もしどうしても特定のJavaScriptファイルを他のJavaScriptファイルよりも結合順を先にしたい場合、そのファイルへのrequireディレクティブをマニフェストの最初に置きます。require
および類似のディレクティブは、出力時に同じファイルを2回以上インクルードしないようになっています。
Railsは以下の行を含むデフォルトのapp/assets/stylesheets/application.css
ファイルも作成します。
/* ... *= require_self *= require_tree . */
Railsはapp/assets/javascripts/application.js
とapp/assets/stylesheets/application.css
ファイルを両方作成します。これはRailsアプリケーション新規作成時に--skip-sprocketsを指定するかどうかにかかわらず行われます。これにより、必要に応じて後からアセットパイプラインを追加することもできます。
JavaScriptで使用できるディレクティブはスタイルシートでも使用できます (なおJavaScriptと異なりスタイルシートは明示的にインクルードされるという違いがあります)。CSSマニフェストにおけるrequire_tree
ディレクティブの動作はJavaScriptの場合と同様に現在のディレクトリにあるすべてのスタイルシートをrequireします。
上の例ではrequire_self
が使用されています。このディレクティブは、require_self
呼び出しが行われた場所にそのファイルが持っているCSSを書き込みます。
Sassファイルを複数使用しているのであれば、Sprocketsディレクティブで読み込まずにSass @import
ルールを使用する必要があります。このような場合にSprocketsディレクティブを使用してしまうと、Sassファイルが自分自身のスコープに置かれるため、その中で定義されている変数やミックスインが他のSassから利用できなくなってしまいます。
@import "*"
や@import "**/*"
などのようにワイルドカードマッチでツリー全体を指定することもできます。これはrequire_tree
と同等です。詳細および重要な警告についてはsass-railsドキュメントを参照してください。
マニフェストファイルは必要に応じていくつでも使用できます。たとえば、アプリケーションのadminセクションで使用するJSファイルとCSSファイルをadmin.css
とadmin.js
マニフェストにそれぞれ記載することができます。
読み込み順についても前述のとおり反映されます。特に、個別に指定したファイルは、そのとおりの順序でコンパイルされます。たとえば、以下では3つのCSSファイルを結合しています。
/* ...
*= require reset
*= require layout
*= require chrome
*/
適用されるプリプロセスの種類は、アセットファイルの拡張子によって決まります。コントローラやscaffoldをデフォルトのgemセットで生成した場合、通常JavaScriptファイルやCSSファイルが置かれる場所にCoffeeScriptファイルとSCSSファイルがそれぞれ生成されます。先の例では、コントローラ名が"projects"で、app/assets/javascripts/projects.coffee
ファイルとapp/assets/stylesheets/projects.scss
ファイルが生成されます。
developmentモードの場合、あるいはアセットパイプラインが無効になっている場合は、これらのアセットへのリクエストはcoffee-script
gemとsass
gemが提供するプロセッサによって処理され、それぞれJavaScriptとCSSとしてブラウザへのレスポンスが送信されます。アセットパイプラインが有効になっている場合は、これらのアセットファイルはプリプロセスの対象となり、処理後のファイルがpublic/assets
ディレクトリに置かれてRailsアプリケーションまたはWebサーバーによって利用されます。
アセットファイル名に別の拡張子を追加することにより、プリプロセス時に別のレイヤを追加でリクエストすることができます。アセットファイル名の拡張子は、「右から左」の順に処理されます。従って、アセットファイル名の拡張子は、これに従って処理を行うべき順序で与える必要があります。たとえば、app/assets/stylesheets/projects.scss.erb
というスタイルシートでは、最初にERBとして処理され、続いてSCSS、最後にCSSとして処理されます。同様にして、 app/assets/javascripts/projects.coffee.erb
というJavaScriptファイルの場合では、ERB → CoffeeScript → JavaScript の順に処理されます。
このプリプロセス順序は非常に重要ですので、心に留めておいてください。たとえば、仮にapp/assets/javascripts/projects.erb.coffee
というファイルを呼び出すと、最初にCoffeeScriptインタプリタによって処理されます。しかしこれは次のERBで処理できないので問題が発生することがあります。
developmentモードの場合、アセットは個別のファイルとして、マニフェストファイルの記載順に読み込まれます。
app/assets/javascripts/application.js
というマニフェストの内容が以下のようになっているとします。
//= require core //= require projects //= require tickets
上によって以下のHTMLが生成されます。
<script src="/assets/core.js?body=1"></script> <script src="/assets/projects.js?body=1"></script> <script src="/assets/tickets.js?body=1"></script>
body
パラメータはSprocketsで必要となります。
sprockets-rails >= 3.2.0を使っている場合は、アセットの探索時に何も見つからなかった場合の挙動を設定できます。「asset fallback」を無効にすると、アセットが見つからない場合にエラーをraiseします。
config.assets.unknown_asset_fallback = false
「asset fallback」を有効にすると、エラーをraiseせずにパスを出力します。アセットのフォールバック動作はデフォルトで有効になっています。
config/environments/development.rb
を更新して以下のようにすることで、ダイジェストをオフにできます。
config.assets.digest = false
このオプションがtrueになっていると、ダイジェストが生成されてアセットへのURLに含まれるようになります。
デバッグモードをオフにするには、config/environments/development.rb
に以下を追記します。
config.assets.debug = false
デバッグモードをオフにすると、Sprocketsはすべてのファイルを結合して、必要なプリプロセッサを実行します。デバッグモードをオフにすると、上のマニフェストファイルによって以下が生成されるようになります。
<script src="/assets/application.js"></script>
アセットは、サーバー起動後に最初にリクエストを受け取った時点でコンパイルとキャッシュが行われます。Sprocketsは、must-revalidate
というCache-Control HTTPヘッダを設定することで、以後のリクエストのオーバーヘッドを減らします。この場合、ブラウザはレスポンス304 (Not Modified) を受け取ります。
リクエストとリクエストの合間に、マニフェストに記載されているファイルのいずれかで変更が生じた場合、Railsサーバーは新しくコンパイルされたファイルをレスポンスで返します。
Railsのヘルパーメソッドを使用してデバッグモードをオンにすることもできます。
<%= stylesheet_link_tag "application", debug: true %> <%= javascript_include_tag "application", debug: true %>
デバッグモードが既にオンの場合、:debug
オプションは冗長です。
developmentモードで健全性チェックの一環として圧縮をオンにしたり、デバッグの必要性に応じてオンデマンドで無効にしたりすることもできます。
Sprocketsは、production環境では前述のフィンガープリントによるスキームを使用します。デフォルトでは、Railsのアセットはプリコンパイル済みかつ静的なアセットとしてWebサーバーから提供されることが前提になっています。
SHA256はコンパイルされるファイルの内容を元にプリコンパイル中に生成され、ファイル名に挿入されてディスクに保存されます。マニフェスト名はRailsヘルパーによってこれらのフィンガープリント名と置き換えられて使用されます。
以下の例で説明します。
<%= javascript_include_tag "application" %> <%= stylesheet_link_tag "application" %>
上のコードによって以下のような感じで生成されます。
<script src="/assets/application-908e25f4bf641868d8683022a5b62f54.js"></script> <link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" media="screen" rel="stylesheet" />
アセットパイプラインの:cache
オプションと:concat
オプションは廃止されました。これらのオプションはjavascript_include_tag
とstylesheet_link_tag
から削除してください。
フィンガープリントの振る舞いについてはconfig.assets.digest
初期化オプションで制御できます。デフォルトではtrue
です。
デフォルトのconfig.assets.digest
オプションは、通常は変更しないでください。ファイル名にダイジェストが含まれないと、遠い将来にヘッダが設定されたときに (ブラウザなどの) リモートクライアントがファイルの内容変更を検出して再度取得することができなくなってしまいます。
Railsには、パイプラインにあるアセットマニフェストなどのファイルを手動でコンパイルするためのタスクが1つバンドルされています。
コンパイルされたアセットは、config.assets.prefix
で指定された場所に保存されます。この保存場所は、デフォルトでは/assets
ディレクトリです。
デプロイ時にこのタスクをサーバー上で呼び出すと、コンパイル済みアセットをサーバー上で直接作成できます。ローカル環境でコンパイルする方法については次のセクションを参照してください。
以下がそのタスクです。
$ RAILS_ENV=production bin/rails assets:precompile
Capistrano (v2.15.1以降) にはデプロイ中にこのタスクを扱うレシピが含まれています。
Capfile
に以下を追加します。
load 'deploy/assets'
これにより、config.assets.prefix
で指定されたフォルダがshared/assets
にリンクされます。
既にこの共有フォルダを使用しているのであれば、独自のデプロイ用タスクを作成する必要があります。
このフォルダは、複数のデプロイによって共有されている点が重要です。これは、サーバー以外の離れた場所でキャッシュされているページが古いコンパイル済みアセットを参照している場合でも、キャッシュ済みページの寿命が来て削除されるまではその古いページへの参照が有効になるようにするためです。
ファイルをコンパイルする際のデフォルトのマッチャによって、app/assets
フォルダ以下のapplication.js
、application.css
、およびすべての非JS/CSSファイル (これにより画像ファイルもすべて自動的にインクルードされます) がインクルードされます。app/assets
フォルダにあるgemも含まれます。
[ Proc.new { |filename, path| path =~ /app\/assets/ && !%w(.js .css).include?(File.extname(filename)) }, /application.(css|js)$/ ]
このマッチャ (および後述するプリコンパイル配列の他のメンバ) が適用されるのは、コンパイル前やコンパイル中のファイル名ではなく、コンパイル後の最終的なファイル名である点にご注意ください。これは、コンパイルされてJavaScriptやCSSになるような中間ファイルはマッチャの対象からすべて除外されるということです (純粋なJavaScript/CSSと同様)。たとえば、.coffee
と.scss
ファイルはコンパイル後にそれぞれJavaScriptとCSSになるので、これらは自動的にはインクルードされません。
他のマニフェストや、個別のスタイルシート/JavaScriptファイルをインクルードしたい場合は、config/initializers/assets.rb
のprecompile
という配列を使用します。
Rails.application.config.assets.precompile += %w( admin.js admin.css )
あるいは、以下のようにすべてのアセットをプリコンパイルすることもできます。
# config/initializers/assets.rb Rails.application.config.assets.precompile << Proc.new do |path| if path =~ /\.(css|js)\z/ full_path = Rails.application.assets.resolve(path).to_path app_assets_path = Rails.root.join('app', 'assets').to_path if full_path.starts_with? app_assets_path logger.info "including asset: " + full_path true else logger.info "excluding asset: " + full_path false end else false end end
プリコンパイル配列にSassやCoffeeScriptファイルなどを追加する場合にも、必ず.js
や.css
で終わるファイル名 (つまりコンパイル後のファイル名として期待されているファイル名) も指定してください。
このタスクによって、すべてのアセットファイルのリストとそれに対応するフィンガープリントを含む.sprockets-manifest-md5hash.json
ファイルも生成されます(md5hash
はMD5ハッシュを意味します)。これは、マッピングのリクエストがSprocketsに戻されるのを回避するためにRailsヘルパーメソッドで使われます。典型的なマニフェストファイルは以下のような感じになります。
{"files":{"application-aee4be71f1288037ae78b997df388332edfd246471b533dcedaa8f9fe156442b.js":{"logical_path":"application.js","mtime":"2016-12-23T20:12:03-05:00","size":412383, "digest":"aee4be71f1288037ae78b997df388332edfd246471b533dcedaa8f9fe156442b","integrity":"sha256-ruS+cfEogDeueLmX3ziDMu39JGRxtTPc7aqPn+FWRCs="}, "application-86a292b5070793c37e2c0e5f39f73bb387644eaeada7f96e6fc040a028b16c18.css":{"logical_path":"application.css","mtime":"2016-12-23T19:12:20-05:00","size":2994, "digest":"86a292b5070793c37e2c0e5f39f73bb387644eaeada7f96e6fc040a028b16c18","integrity":"sha256-hqKStQcHk8N+LA5fOfc7s4dkTq6tp/lub8BAoCixbBg="}, "favicon-8d2387b8d4d32cecd93fa3900df0e9ff89d01aacd84f50e780c17c9f6b3d0eda.ico":{"logical_path":"favicon.ico","mtime":"2016-12-23T20:11:00-05:00","size":8629, "digest":"8d2387b8d4d32cecd93fa3900df0e9ff89d01aacd84f50e780c17c9f6b3d0eda","integrity":"sha256-jSOHuNTTLOzZP6OQDfDp/4nQGqzYT1DngMF8n2s9Dto="}, "my_image-f4028156fd7eca03584d5f2fc0470df1e0dbc7369eaae638b2ff033f988ec493.png":{"logical_path":"my_image.png","mtime":"2016-12-23T20:10:54-05:00","size":23414, "digest":"f4028156fd7eca03584d5f2fc0470df1e0dbc7369eaae638b2ff033f988ec493","integrity":"sha256-9AKBVv1+ygNYTV8vwEcN8eDbxzaequY4sv8DP5iOxJM="}}, "assets":{"application.js":"application-aee4be71f1288037ae78b997df388332edfd246471b533dcedaa8f9fe156442b.js", "application.css":"application-86a292b5070793c37e2c0e5f39f73bb387644eaeada7f96e6fc040a028b16c18.css", "favicon.ico":"favicon-8d2387b8d4d32cecd93fa3900df0e9ff89d01aacd84f50e780c17c9f6b3d0eda.ico", "my_image.png":"my_image-f4028156fd7eca03584d5f2fc0470df1e0dbc7369eaae638b2ff033f988ec493.png"}}
マニフェストのデフォルトの置き場所は、config.assets.prefix
で指定された場所のルートディレクトリ (デフォルトでは'/assets') です。
productionモードで見つからないプリコンパイル済みファイルがあると、見つからないファイル名をエラーメッセージに含んだSprockets::Helpers::RailsHelper::AssetPaths::AssetNotPrecompiledError
が発生します。
プリコンパイル済みのアセットはファイルシステム上に置かれ、Webサーバーから直接クライアントに提供されます。これらプリコンパイル済みアセットには、いわゆる遠い将来に期限切れになるヘッダ (far-future headers) はデフォルトでは含まれていません。したがって、フィンガープリントのメリットを得るためには、サーバーの設定を更新してこのヘッダを含める必要があります。
Apacheの設定:
# Expires* ディレクティブを使用する場合はApacheの # `mod_expires`モジュールを有効にする必要あり <Location /assets/> # Last-Modifiedフィールドが存在する場合はETagの使用が妨げられる Header unset ETag FileETag None # RFCによるとキャッシュは最長1年まで ExpiresActive On ExpiresDefault "access plus 1 year" </Location>
NGINXの場合:
location ~ ^/assets/ { expires 1y; add_header Cache-Control public; add_header ETag ""; }
ファイルをプリコンパイルする際に、Sprocketsによってgzipされた (.gz) アセットも作成されます。Webサーバーによる圧縮はほどほどの圧縮率で行われるのが普通ですが、プリコンパイルが1度発生するとSprocketsによって最大圧縮率で圧縮され、Webサーバーからのデータ転送量が最小化されます。逆に、圧縮されてないファイルを自前で圧縮する代りに、事前に圧縮しておいたコンテンツを直接ディスクに配置しておくようWebサーバーを設定することもできます。
NGINXではgzip_static
を使用することでこれを自動的に行なうことができます。
location ~ ^/(assets)/ { root /path/to/public; gzip_static on; # gzip済みのバージョンを提供する expires max; add_header Cache-Control public; }
このディレクティブは、この機能を提供するコアモジュールがWebサーバーと一緒にコンパイルされている場合に使用可能になります。Ubuntu/Debianパッケージはもちろん、nginx-light
にもこのモジュールがコンパイル済みで用意されています。それ以外の場合には、自分でコンパイルを行う必要があるでしょう。
./configure --with-http_gzip_static_module
NGINXをPhusion Passengerと共にコンパイルする場合は、コンパイル中にプロンプトが表示された時にそのためのオプションを渡す必要があります。
Apacheで堅牢な設定を行なうことは可能ですが、何かとトリッキーであるため、ネットを検索して情報を十分集めてください。(Apache用のよい設定例を確立したら本ガイドに反映いただけると大変助かります)
アセットをローカルでプリコンパイルする理由はいくつか考えられます。たとえば以下のようなものがあります。
ローカルでのコンパイルを行なうことで、コンパイル済みのアセットファイルをGitなどによるソース管理対象に含め、他のファイルと一緒にデプロイできるようになります。
ただし、以下の3つの注意点があります。
config/environments/development.rb
に以下の行があります。
config.assets.prefix = "/dev-assets"
prefix
を変更すると、Sprocketsはdevelopmentモードで別のURLを使用してアセットを提供し、すべてのリクエストがSprocketsに渡されるようになります。production環境のプレフィックスは/assets
のままです。この変更を行わなかった場合、アプリケーションはdevelopment環境でもproduction環境と同じ/assets
からプリコンパイルしたアセットを提供します。この場合、アセットを再コンパイルしないとローカルでの変更が反映されません。
実用上は、この変更によってローカルでのプリコンパイルが行えるようになり、必要に応じてそれらのファイルをワーキングツリーに追加してソース管理にコミットできるようになります。developmentモードは期待どおり動作します。
状況によっては動的コンパイル (live compilation) を使用したいこともあるでしょう。このモードでは、パイプラインのアセットへのリクエストは直接Sprocketsによって扱われます。
このオプションを有効にするには以下を設定します。
config.assets.compile = true
最初のリクエストを受けると、アセットは上述のdevelopment環境のところで説明したとおりにコンパイルおよびキャッシュされます。ヘルパーで使用されるマニフェスト名にはSHA256ハッシュが含まれます。
また、SprocketsはCache-Control
HTTPヘッダーをmax-age=31536000
に変更します。このヘッダーは、サーバーとクライアントブラウザの間にあるすべてのキャッシュ (プロキシなど) に対して、サーバーが提供するこのコンテンツは1年間キャッシュしてよいと通知します。これにより、そのサーバーのアセットに対するリクエスト数を減らすことができ、アセットをローカルブラウザのキャッシュやその他の中間キャッシュで代替するよい機会が与えられます。
このモードはデフォルトよりもメモリを余分に消費し、パフォーマンスも落ちるためお勧めできません。
本番アプリケーションのデプロイ先のシステムに既存のJavaScriptランタイムがない場合は、以下をGemfileに記述します。
group :production do gem 'mini_racer' end
CDN (コンテンツデリバリーネットワーク)は、全世界を対象としてアセットをキャッシュすることを主な目的として設計されています。それにより、ブラウザからアセットをリクエストすると、ネットワーク上で最も近くにあるキャッシュのコピーが使用されます。production環境のRailsサーバーから (中間キャッシュを使用せずに) 直接アセットを提供しているのであれば、アプリケーションとブラウザの間でCDNを使用するのがベストプラクティスです。
CDNの典型的な利用法は、productionサーバーを "origin" サーバーとして設定することです。つまり、ブラウザがCDN上のアセットをリクエストしてキャッシュが見つからない場合、オンデマンドでサーバーからアセットファイルを取得してキャッシュするということです。たとえば、Railsアプリケーションをexample.com
というドメインで運用しており、mycdnsubdomain.fictional-cdn.com
というCDNが設定済みであるとします。mycdnsubdomain.fictional-cdn.com/assets/smile.png
がリクエストされると、CDNはいったん元のサーバーのexample.com/assets/smile.png
にアクセスしてこのリクエストをキャッシュします。CDN上の同じURLに対して次のリクエストが発生すると、キャッシュされたコピーがヒットします。CDNがアセットを直接提供する場合、ブラウザからのリクエストが直接Railsサーバーに達することはありません。CDNが提供するアセットはネットワーク上でブラウザに近い位置にあるので、リクエストは高速化されます。また、サーバーはアセットの送信に使う時間を節約できるので、アプリケーション本来のコードをより高速で提供することに集中できます。
CDNを設定するには、Railsアプリケーションがインターネット上でproductionモードで運用されており、example.com
などのように誰でもアクセスできるURLがある必要があります。続いて、クラウドホスティングプロバイダーが提供するCDNサービスと契約を結ぶ必要もあります。その際、CDNの"origin"設定をRailsアプリケーションのWebサイトexample.com
にする必要もあります。originサーバーの設定方法のドキュメントについてはプロバイダーにお問い合わせください。
サービスに使用するCDNから、アプリケーションで使用するためのカスタムサブドメイン (例: mycdnsubdomain.fictional-cdn.com
) を交付してもらう必要もあります (メモ: fictional-cdn.comは説明用であり、少なくとも執筆時点では本当のCDNプロバイダーではありません)。以上でCDNサーバーの設定が終わりましたので、今度はブラウザに対して、Railsサーバーに直接アクセスするのではなく、CDNからアセットを取得するように通知する必要があります。これを行なうには、従来の相対パスに代えてCDNをアセットのホストサーバーとするようRailsを設定します。Railsでアセットホストを設定するには、config/environments/production.rb
のconfig.action_controller.asset_host
を以下のように設定します。
config.action_controller.asset_host = 'mycdnsubdomain.fictional-cdn.com'
ここに記述するのは "ホスト名" (サブドメインとルートドメインを合わせたもの) のみです。http://
やhttps://
などのプロトコルスキームを記述する必要はありません。アセットへのリンクで使用されるプロトコルスキームは、Webページヘのリクエスト発生時に、そのページへのデフォルトのアクセス方法に合わせて適切に生成されます。
この値は環境変数で設定することもできます。これを使用すると、ステージングサーバー (訳注: 検証用に本番サーバーを複製したサーバー) の実行が楽になります。
config.action_controller.asset_host = ENV['CDN_HOST']
上の設定が有効になるためには、サーバーのCDN_HOST
環境変数に値 (この場合であればmycdnsubdomain.fictional-cdn.com
) を設定しておく必要があります。
サーバーとCDNの設定完了後、以下のアセットを持つWebページにアクセスしたとします。
<%= asset_path('smile.png') %>
上の例では、/assets/smile.png
のようなパスは返されません (読みやすくするためダイジェスト文字は省略してあります)。実際に生成されるCDNへのフルパスは以下のようになります。
http://mycdnsubdomain.fictional-cdn.com/assets/smile.png
smile.png
のコピーがCDNにあれば、CDNが代りにこのファイルをブラウザに送信します。元のサーバーはリクエストがあったことすら知りません。ファイルのコピーがCDNにない場合、CDNは "origin" (この場合example.com/assets/smile.png
) を探して今後のために保存しておきます。
CDNで扱うアセットを一部だけに限っておきたい場合、アセットヘルパーのカスタム:host
オプションを使用してconfig.action_controller.asset_host
の値セットを上書きすることもできます。
<%= asset_path 'image.png', host: 'mycdnsubdomain.fictional-cdn.com' %>
CDNはコンテンツをキャッシュすることで動作します。CDNに保存されているコンテンツが古くなったり壊れていたりすると、メリットよりも害の方が大きくなります。本セクションでは、多くのCDNにおける一般的なキャッシュの動作について解説します。プロバイダによってはこの記述のとおりでないことがありますのでご注意ください。
これまでCDNがアセットをキャッシュするのに向いていると説明しましたが、実際にキャッシュされているのはアセット単体ではなくリクエスト全体です。リクエストにはアセット本体の他に各種ヘッダーも含まれています。ヘッダーの中でもっとも重要なのはCache-Control
です。これはCDN (およびWebブラウザ) にキャッシュの取り扱い方法を通知するためのものです。たとえば、誰かが実際には存在しないアセット/assets/i-dont-exist.png
にリクエストを行い、Railsが404エラーを返したとします。このときにCache-Control
ヘッダーが有効になっていると、CDNはこの404エラーページをキャッシュしようとします。
このヘッダが正しくキャッシュされているかどうかを確認するひとつの方法として、curlを使用するという方法があります。curlを使用して、サーバーとCDNにそれぞれリクエストを送信し、ヘッダーが同じであるかどうかを以下のように確認できます。
$ curl -I http://www.example/assets/application-d0e099e021c95eb0de3615fd1d8c4d83.css HTTP/1.1 200 OK Server: Cowboy Date: Sun, 24 Aug 2014 20:27:50 GMT Connection: keep-alive Last-Modified: Thu, 08 May 2014 01:24:14 GMT Content-Type: text/css Cache-Control: public, max-age=2592000 Content-Length: 126560 Via: 1.1 vegur
今度はCDNのコピーです。
$ curl -I http://mycdnsubdomain.fictional-cdn.com/application-d0e099e021c95eb0de3615fd1d8c4d83.css HTTP/1.1 200 OK Server: Cowboy Last-Modified: Thu, 08 May 2014 01:24:14 GMT Content-Type: text/css Cache-Control: public, max-age=2592000 Via: 1.1 vegur Content-Length: 126560 Accept-Ranges: bytes Date: Sun, 24 Aug 2014 20:28:45 GMT Via: 1.1 varnish Age: 885814 Connection: keep-alive X-Served-By: cache-dfw1828-DFW X-Cache: HIT X-Cache-Hits: 68 X-Timer: S1408912125.211638212,VS0,VE0
CDNが提供するX-Cache
などの機能やCDNが追加するヘッダなどの付加的情報については、CDNのドキュメントを確認してください。
Cache-Controlヘッダは、リクエストがキャッシュされる方法を定めたW3Cの仕様です。CDNを使用していない場合、ブラウザはこのヘッダ情報を使用してコンテンツをキャッシュします。このヘッダのおかげで、アセットで変更が発生していない場合にブラウザがCSSやJavaScriptをリクエストのたびに再度ダウンロードせずに済み、非常に有用です。アセットのCache-Controlヘッダは一般に "public" にしておくものであり、RailsサーバーはCDNやブラウザに対してこのヘッダを通じてそのことを通知します。アセットが "public" であるということは、そのリクエストをどんなキャッシュにも保存してよいということを意味します。同様にmax-age
もこのヘッダでCDNやブラウザに通知されます。max-age
は、キャッシュがオブジェクトを保存する期間を指定します。この期間を過ぎるとキャッシュは廃棄されます。max-age
の値は秒単位で指定します。最大値は31536000
であり、これは一年に相当します。Railsでは以下の設定でこの期間を指定できます。
config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=31536000' }
production環境のアセットは上の設定によってアプリケーションから提供されるようになり、キャッシュは1年間保存されます。多くのCDNはリクエストのキャッシュも保存しているので、このCache-Control
ヘッダーはアセットをリクエストするすべてのブラウザ (将来登場するブラウザも含める) に渡されます。ブラウザはこのヘッダを受け取ると、次回再度リクエストが必要になったときに備えてそのアセットを当分の間キャッシュに保存してよいことを知ります。
多くのCDNでは、アセットのキャッシュを完全なURLに基いて行います。たとえば以下のアセットへのリクエストがあるとします。
http://mycdnsubdomain.fictional-cdn.com/assets/smile-123.png
上のリクエストのキャッシュは、下のアセットへのリクエストのキャッシュとは完全に異なるものとして扱われます。
http://mycdnsubdomain.fictional-cdn.com/assets/smile.png
Cache-Control
のmax-age
を遠い将来に設定する場合は、アセットに変更が生じた時にこれらのキャッシュが確実に廃棄されるようにしてください。たとえば、ニコニコマーク画像の色を黄色から青に変更したら、サイトを訪れた人には変更後の青いニコニコマークが見えるようにしたいはずです。RailsをCDNを併用している場合、Railsのアセットパイプラインconfig.assets.digest
はデフォルトでtrueに設定されるので、アセットの内容に少しでも変更が生じれば必ずファイル名も変更されます。このとき、キャッシュ内の項目を手動で削除する必要がまったくない点にご注目ください。アセット名が内容に応じて常に一意になるので、ユーザーは常に最新のアセットを利用できます。
YUIはCSS圧縮方法のひとつです。YUI CSS compressorは最小化機能を提供します (訳注: この項では、圧縮 (compress) という語は最小化 (minify) や難読化 (uglify) と同じ意味で使用されており、圧縮後のファイルはzipのようなバイナリになりません)。
YUI圧縮は以下の記述で有効にできます。これにはyui-compressor
gemが必要です。
config.assets.css_compressor = :yui
sass-rails gemを使用している場合は、以下のように代替のCSS圧縮方法として指定できます。
config.assets.css_compressor = :sass
JavaScriptを圧縮する際には:closure
、:uglifier
、:yui
のいずれかのオプションを指定できます。それぞれ、closure-compiler
gem、uglifier
gem、yui-compressor
gemが必要です。
RailsのGemfile
にはデフォルトでuglifierが含まれています。このgemは、NodeJSで記述されたUglifyJSをRubyでラップしたものです。uglifierによる圧縮は次のように行われます。ホワイトスペースとコメントを除去し、ローカル変数名を短くし、可能であればif
とelse
を三項演算子に置き換えるなどの細かな最適化を行います。
以下の設定により、JavaScriptの圧縮にuglifier
が使用されます。
config.assets.js_compressor = :uglifier
uglifier
を利用するにはExecJSをサポートするJavaScriptランタイムが必要です。macOSやWindowsを使用している場合は、OSにJavaScriptランタイムをインストールしてください。
デフォルトで、非圧縮版のアセットの他にgzipで圧縮されたコンパイル済みアセットが生成されます。gzipアセットはデータ転送の削減に役立ちます。これを指定するにはgzip
フラグを設定します。
config.assets.gzip = false # disable gzipped assets generation
CSSやJavaScriptの圧縮設定にはあらゆるオブジェクトを設定できます。設定に与えるオブジェクトにはcompress
メソッドが実装されている必要があります。このメソッドは文字列のみを引数として受け取り、圧縮結果を文字列で返す必要があります。
class Transformer def compress(string) do_something_returning_a_string(string) end end
上のコードを有効にするには、application.rb
の設定オプションに新しいオブジェクトを渡します。
config.assets.css_compressor = Transformer.new
デフォルトでは、Sprocketsが使用するパブリックなパスは/assets
になります。
このパスは以下のように変更可能です。
config.assets.prefix = "/他のパス"
このオプションは次のような場合に便利です。アセットパイプラインを使用しない既存のプロジェクトがあり、そのプロジェクトの既存のパスを指定したり、別途新しいリソース用のパスを指定したりする場合です。
X-SendfileヘッダーはWebサーバーに対するディレクティブであり、アプリケーションからのレスポンスをブラウザに送信せずに破棄し、代りに別のファイルをディスクから読みだしてブラウザに送信します。このオプションはデフォルトでは無効です。サーバーがこのヘッダーをサポートしていればオンにできます。このオプションをオンにすると、それらのファイル送信はWebサーバーに一任され、それによって高速化されます。この機能の使用法についてはsend_fileを参照してください。
ApacheとNGINXではこのオプションがサポートされており、以下のようにconfig/environments/production.rb
で有効にすることができます。
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # Apache用 # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # NGINX用
既存のRailsアプリケーションをアップグレードする際にこの機能を使用することを検討している場合は、このオプションの貼り付け先に十分ご注意ください。このオプションを貼り付けてよいのはproduction.rb
と、production環境として振る舞わせたい他の環境ファイルのみです。application.rb
ではありません。
デフォルトのSprocketsは、development環境とproduction環境でtmp/cache/assets
にあるアセットをキャッシュします。これは以下のように変更できます。
config.assets.configure do |env| env.cache = ActiveSupport::Cache.lookup_store(:memory_store, { size: 32.megabytes }) end
アセットキャッシュストアを無効にするには以下のようにします。
config.assets.configure do |env| env.cache = ActiveSupport::Cache.lookup_store(:null_store) end
アセットはgemの形式で外部ソースから持ち込むこともできます。
そのよい例はjquery-rails
gemです。これは標準のJavaScriptライブラリをgemとしてRailsに提供します。このgemにはRails::Engine
から継承したエンジンクラスが1つ含まれています。このgemを導入することにより、Railsはこのgem用のディレクトリにアセットを配置可能であることを認識し、app/assets
、lib/assets
、vendor/assets
ディレクトリがSprocketsの検索パスに追加されます。
Sprocketsでは機能を拡張するのにProcessors、Transformers、Compressors、Exportersを使います。詳しくはExtending Sprocketsをご覧ください。ここではtext/css (.css
)ファイルの末尾にコメントを追加するプリプロセッサを登録しました。
module AddComment def self.call(input) { data: input[:data] + "/* Hello From my sprockets extension */" } end end
これで入力データを変更するモジュールができましたので、続いてMIMEタイプのプリプロセッサとして登録しましょう。
Sprockets.register_preprocessor 'text/css', AddComment
Rails 3.0やRails 2.xからのアップグレードの際には、いくつかの作業を行う必要があります。最初に、public/
ディレクトリ以下のファイルを新しい場所に移動します。ファイルの種類ごとの正しい置き場所については、アセットの編成を参照してください。
続いて、JavaScriptファイルの重複を解消します。jQueryはRails 3.1以降におけるデフォルトのJavaScriptライブラリなので、jquery.js
をapp/assets
に置かなくても自動的に読み込まれます。
3番目に、多くの環境設定ファイルを正しいデフォルトオプションに更新します。
application.rb
の場合。
# アセットのバージョンを指定する。アセットをすべて期限切れにしたい場合はこの値を変更する。 config.assets.version = '1.0' # config.assets.prefix = "/assets"は、アセットの置き場所となるパスを変更する際に使用する。
development.rb
の場合。
# アセットで読み込んだ行を展開する。 config.assets.debug = true
production.rb
の場合。
# 使うコンプレッサを選択する(ある場合) config.assets.js_compressor = :uglifier # config.assets.css_compressor = :yui # プリコンパイル済みのアセットが見当たらない場合にアセットパイプラインにフォールバックしない config.assets.compile = false # アセットURLのダイジェストを生成する。 config.assets.digest = true # 追加のアセットをプリコンパイルする (application.js、application.css、およびすべての # 非JS/CSSファイルが追加済み) # config.assets.precompile += %w( admin.js admin.css )
Rails 4以降では、Sprocketsのデフォルト設定値をtest環境用のtest.rb
に設定しなくなりました。従って、test.rb
にSprocketsの設定を行なう必要があります。test環境における以前のデフォルト値は、config.assets.compile = true
、config.assets.compress = false
、config.assets.debug = false
、config.assets.digest = false
です。
以下をGemfile
に追加する必要があります。
gem 'sass-rails', "~> 3.2.3" gem 'coffee-rails', "~> 3.2.1" gem 'uglifier'
Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。
原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨
本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。
Railsガイド運営チーム (@RailsGuidesJP)
Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。