ども、@kimihom です。
Rails で開発していると、assets/javascripts
内で定義したメソッドを View 内に書かれた <script>
タグから呼び出したい時がある。Rails は基本的に assets/javascript
内のコードを全てひとまとめにして一つのapplication.js
ってのを作るから、特定のページのロード完了後に特定の JavaScript コードを呼び出したい時にちょっと困ることになる。そんな時は View 内に <script>
タグを入れる必要が出てくるだろう。
View 内と Assets 内の JavaScript の混在による課題
だが、View と Assets 内に JavaScript を混在させるといろいろな問題が出てくる。そう簡単にはいかない問題だ。
外部ライブラリの読み込みの前にメソッドを呼んでしまう
jQuery のような JavaScript ライブラリは、より早く HTML を表示させるために <head>
タグではなく、<body>
の一番下に書くことがあると思う。そうなると、レイアウト内の yield
の後に jQuery が読み込まれることになる。つまり、View 内でベタ書きした <script>
タグの方がライブラリよりも先に呼ばれてしまうことになる。これはよろしくない。
app/views/layouts/application.html.erb
<html> <head> <title>Sample App</title> <%= stylesheet_link_tag 'application', media: 'all' %> <%= csrf_meta_tags %> </head> <body> <%= yield %> <%= javascript_include_tag 'application' %> </body> </html>
app/views/users/index.html.erb
<div id="users"> ..... </div> <script> $("#users").... // <- "$" が呼び出せない!! </script>
ソースコードのカオス化
View 内に <script>
タグをどんどん入れて行ってしまったり、ロジックをその中にベタ書きしてしまうと、assets/javascripts
にある JavaScript ファイルとごちゃごちゃになってメンテナンス困難なソースコードが出来上がってしまう。
だからできれば assets/javascripts
内に JavaScript のコードを集約させたい。
View から Assets 内の JavaScript を呼び出せない
かといって、assets/javascripts
内で functions を定義しても、Rails の AssetPipeline による JavaScript の Minify によってメソッド名を指定することができない。
app/assets/javascripts/users.js
function setUser() { ...... }
app/views/users/index.html.erb
<div id="users"> ..... </div> <script> $(function() { setUser(); // <- "setUser" が呼び出せない!! }); </script>
content_for
と trigger
によって解決しよう
さて、本記事のメインテーマである解決策を掲示しよう。まずは1点目の <script>
タグの読み込み順について。これは content_for
を使うことで解決できる。
app/views/layouts/application.html.erb
<html> <head> <title>Sample App</title> <%= stylesheet_link_tag 'application', media: 'all' %> <%= csrf_meta_tags %> </head> <body> <%= yield %> <%= javascript_include_tag 'application' %> <%= yield :footer %> </body> </html>
app/views/users/index.html.erb
<div id="users"> ..... </div> <%= content_for :footer do %> <script> $("#users").... // <- "$" が呼び出せる! </script> <% end %>
これで、 jQuery が読み込まれた後に、 <script>
タグを読み込ませることができる。
続いて JavaScript の Minify によって指定のメソッドが呼び出せない問題。これは trigger
を定義してあげよう。
app/assets/javascripts/users.js
$(function() { $(document).on("users:loaded", "#users", function() { //..... }); });
app/views/users/index.html.erb
<div id="users"> ..... </div> <script> <%= content_for :footer do %> <script> $("#users").trigger("users:loaded"); </script> <% end %>
trigger
には引数を与えることもできるので、とても柔軟に View と Assets の JavaScript を通信することが可能だ。
Rails の content_for
と jQuery の trigger
によって、個別 View のロード時に特定の JavaScript を実行することができるようになった。
終わりに
trigger
はいろいろと応用が利くとても便利な jQuery メソッドだ。より詳しく知りたい方は以下の記事も参照されるといいだろう。
今更ながら jQuery の trigger の魅力について語らせてもらう
Rails のレールに乗った美しいコーディングを目指していこう。