(2015年までの)odaillyjp blog

イベント参加記録とプログラミング系の雑記

パーフェクト Rails を読みました(3章)

この記事は『パーフェクト Rails を読みました』シリーズの3回目の記事です。
1回目の記事は『パーフェクト Rails を読みました(1章) - Programming log - Shindo200』です。
2回目の記事は『パーフェクト Rails を読みました(2章) - Programming log - Shindo200』です。

今日も『パーフェクト Ruby on Rails』を読んでいきます。

パーフェクト Ruby on Rails

パーフェクト Ruby on Rails

3章の感想

3章では Sprockets、CoffeeScript、Sass、Turbolinks について学んでいきます。まずは Sprokets から始まるのですが、Rack アプリケーションとして動かしながら体系的に学んでいくので、Rails 初心者でもわかりやすいです。CoffeeScript や Sass の構文についても、それぞれ10ページくらい使って解説されています。Sprockets、CoffeeScript、Sass は Rails 3.1 で加わった機能で、今ではだいぶ使われていると思うのですが、RailsTutorial などの入門者向け資料ではあまり触れられていませんでした。ここでしっかり学んでおきたいです。Turbolinks を使うとページ遷移を高速にすることができますが、だいぶ慣れが必要そうに感じました。
(合わせて読みたい記事: Rails - Turbolinksをオフしないためにやった事 - Qiita

備忘録

Sprockets

画像ファイルや JavaScript や Stylesheet など、Webアプリケーションの直接のレスポンスではない構成要素をアセットと呼びます。このアセットファイルにアクセスするためのパスを管理したり、コンパイルする機能を提供するのが Sprockets という gem です。

README.md の「Serving Assets Over HTTP」部分を読むと、使い方がわかると思います。

以前、『uglifier とは何をする gem なのか - Programming log - Shindo200』という記事で「Rails がどのタイミングで uglifier を動かしているのかはわからないのですが〜」と書いたのですが、アクセスが来たときやプレコンパイル機能が動いたときに Sprockets が uglifier を呼び出して JavaScript のコードを軽量化しているようですね。

environment.js_compressor  = :uglify

Sprockets による依存性の管理

Sprockets にはアセットファイルの依存性を管理する機能があります。依存するファイルはコメントに「= ファイル名」と書くことで指定できます。

//= require jquery

このファイルにアクセスすると、Sprockets は管理されているアセットパス下から「jquery.js」というファイルがあるか探しにいくそうです。

Railsアプリケーションの場合は app/assets/javascripts/application.js や app/assets/stylesheets/application.css にこのような記述があります。これらはマニフェストファイルというファイルだそうです。(詳しくは『パーフェクト Ruby on Rails』 P.100 で。)それぞれの中身を確認してみます。

app/assets/javascripts/application.js

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

app/assets/stylesheets/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 vendor/assets/stylesheets of plugins, if any, 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」「require_self」という構文が出てきました。「require_tree」と「require_self」はそれぞれ以下のような動きをします。(『パーフェクト Ruby on Rails』P.100 表3.1 を参考にまとめました。)

構文名 説明
require_tree 引数として与えられたディレクトリ下を再帰的に検索して、同じフォーマットのファイルを自身より前に挿入する。挿入される順番はアルファベット順になる
require_self 自身のファイル内容を挿入する。複数のディレクティブを記述している時に、自身が読み込まれる順番を指定したい場合に利用する

application.js の方は

  • jquery を読む込む
  • jquery_ujs を読む込む
  • turbolinks を読み込む
  • app/assets/javascripts/ 下にあるファイルを読み込む

という順番で処理を行います。application.css の方は

  • app/assets/stylesheets/ 下にあるファイルを読み込む
  • 自身のファイルを読み込む

という順番で処理を行います。

application.css は「require_tree .」が先?

先ほど Rails 4.1.1 で生成した application.css の中身を確認してみましたが、『パーフェクト Ruby on Rails』P.101 リスト3.12 では次のように書かれています。

リスト3.12 app/assets/stylesheets/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 vendor/assets/stylesheets of plugins, if any, 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 top of the
 * compiled file, but it's generally better to create a new file per style scope.
 *
 *= require_self
 *= require_tree .
 */

書籍の application.css では「require_self」が「require_tree .」より先に書かれています。Rails 4.1.1 で生成した application_css と中身が違うのですが、これは何なのでしょうか。どうやら、Rails 4.1.0 から「require_tree .」が先に読み込まれるように変わったみたいです。application.css に定義した値を優先したかったのに、DHH が勘違いで実装していて、Rails 4.1.0 でそれを修正したという感じでしょうか。

参考: Changed stylesheet load order in the stylesheet manifest generator. by pawel2105 · Pull Request #11640 · rails/rails · GitHub

Source maps

coffee-rails-source-maps という gem を使うと、JavaScript のコードと CoffeeScript のコードの対応関係が書かれたマッピングファイルを出力してくれるようになります。

試しに RailsTutorial で作ったサンプルアプリケーションに導入してみました。
f:id:Shindo_Masaya:20140605112330j:plain:w600
本来はコンパイルされた JavaScript のコードでの行数が表示されますが、CoffeeScript のコードでの行数が表示されていますね。

あとがき

今のところ、1章あたり3時間くらいのペースで読んでいます。4章も頑張ります。