とあるJavascriptを特定のページ(とあるcontrollerのとあるaction)でだけロードして実行したい
いろいろハマったので、メモ。Railsは4.1.1。初級者なので、個々の用語や表現は厳密ではない(かもしれない)のでご注意を。
やりたいこと
とあるJavascriptを特定のページ(とあるcontrollerのとあるaction)でだけロードして実行したい。
壁
本稿執筆時点のRailsには以下2機能が存在し、デフォルトで有効になっている。
- Asset Pipeline
- 複数のjavascriptやcssのファイルをマージ・圧縮し、読み込みを高速化する機能
- Turbolinks
- ページ遷移をAjaxに置き換えて表示を高速化する機能
とても便利な機能だが、「とあるJavascriptを特定のページでだけロードして実行したい」という望みとの相性が悪い。というのも、
- Asset Pipeline
- jsファイルを小分けにしても、一つのファイルにマージされてしまう。
- Turbolinks
- ページ遷移時はheadとbodyをJavascriptにて書き換えており、linkタグなどが再解釈されて読み込まれるわけではない。
という動作のため。(あくまでイメージということで…)
対策
下記すべての合わせ技で実現する。
- 読み込ませたいjsファイルを、Asset Pipelineの対象から外す
- 読み込ませたいjsファイルを、precompile対象に追加する
- 読み込ませたいjsファイルを、Turbolinksの対象から外す
- app/views/layouts/application.html.erbにて、「特定のページのときだけ」対象のjsファイルをincludeする記述を追加する
読み込ませたいjsファイルを、Asset Pipelineの対象から外す
まず、読み込ませたいjsファイル(以下、hoge.js)を、app/assets/javascript/配下に置く。
そして、app/assets/javascript/application.jsに下記を追記する。
//= stub hoge
読み込ませたいjsファイルを、precompile対象に追加する
config/initialize/assets.rbに、hoge.jsについての記述を追加する。
Rails.application.config.assets.precompile += %w( hoge.js )
こうすることで、view側でjavascript_include_tagで読み込めるようになる。
読み込ませたいjsファイルを、Turbolinksの対象から外す
「data-turbolinks-track」オプションを付与することで実現可能。
おそらく、これが含まれているタグがあるページヘの遷移は、Ajaxじゃなく通常遷移するような作りになっているのではないかと推測(調べていない)。
<%= javascript_include_tag "hoge", 'data-turbolinks-track' => true %>
app/views/layouts/application.html.erbにて、「特定のページのときだけ」対象のjsファイルをincludeする記述を追加する
上記javascript_include_tagに、適当な条件を付与する。方法は色々。今回は最後の手法を用いてみた。作法的には良くないのかもしれないけど、provideを使った。
- app/views/layouts/application.html.erbのbodyタグのidやclassにcontroller名、action名を付与するようにし、狙った組み合わせになったときにだけ読み込ませるようにする。
- ルーティングに基いて、狙ったルートのときだけ読み込ませるようにする。
- とある変数が定義されていたときだけ読み込ませるようにする。
まず、app/views/layouts/application.html.erbを下記のように変更、
<%= javascript_include_tag "hoge", 'data-turbolinks-track' => true if content_for?(:use_hoge) %>
次に、対象のviewの先頭に下記を追加。
<% provide(:use_hoge, true) %>