基本用語
モックアップ
実装後のアプリケーションの外観をスケッチしたもの。ワイヤーフレームとも呼ばれる。
文法
IEのバージョンが9未満の場合にのみHTML5 shimを読み込む
RailsはデフォルトでHTML5を使う (<!DOCTYPE html>と書いてHTML5であることを宣言する)。
ただHTML5は比較的新しく、一部のブラウザ (特に旧式のInternet Explorer) ではHTML5のサポートが不完全である場合がある。
そのためJavaScriptのコード (通称: HTML5 shim (or shiv))を使ってこの問題を回避する。
<!DOCTYPE html>
<html>
<head>
.
.
.
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
</script>
<![endif]-->
</head>
.
.
.
link_to
link_toの第1引数はリンクテキスト、第2引数はURL、第3引数はオプションハッシュで、この場合はサンプルアプリのリンクでCSS id logoを指定している(第3引数必須ではない)。
# Railsヘルパー
<%= link_to "sample app", '#', id: "logo" %>
# ブラウザに返されるHTML
<a id="logo" href="#">sample app</a>
image_tag
Railsは該当する画像ファイルを、アセットパイプラインを通してapp/assets/images/ディレクトリの中から探してくれる。
# Railsヘルパー
<%= image_tag("rails.png", alt: "Rails logo") %>
# ブラウザに返されるHTML
<img alt="Rails logo" src="/assets/rails-c094bc3a4bf50e5bb477109e5cb0d213af27ad75b481c4df249f50974dbeefe6.png">
src属性には "images" というディレクトリ名が含まれていないが、これは高速化のための仕組みで、Railsはassetsディレクトリ直下の画像をapp/assets/imagesディレクトリにある画像と紐付けている。
これにより、ブラウザから見るとすべてのファイルが同じディレクトリにあるように見えるようになる。
link_toと組み合わせて画像のリンクを生成することも可能。
# Railsヘルパー
<%= link_to image_tag("rails.png", alt: "Rails logo"),
'http://rubyonrails.org/' %>
# ブラウザに返されるHTML
<a href="http://rubyonrails.org/">
<img alt="Rails logo" src="/assets/rails-c094bc3a4bf50e5bb477109e5cb0d213af27ad75b481c4df249f50974dbeefe6.png">
</a>
画像をダウンロードする
curl -o app/assets/images/rails.png -OL railstutorial.jp/rails.png
ファイルを移動する
mv 移動元 移動先
mv kitten.jpg app/assets/images
埋め込みRubyのコードをコメントアウトする
<%#= image_tag("kitten.jpg", alt: "Kitten") %>
テスト環境でApplicationヘルパーを使う
ENV['RAILS_ENV'] ||= 'test'
.
.
.
class ActiveSupport::TestCase
fixtures :all
include ApplicationHelper # テスト環境でApplicationヘルパーを使う
.
.
.
end
Bootstrap
Bootstrapを使うことでアプリケーションをレスポンシブデザイン (Responsive Design) にできる。
Bootstrapを追加
Bootstrapフレームワークでは、動的なスタイルシートを生成するためにLESS CSS言語を使っているが、RailsのAsset Pipelineはデフォルトでは (LESSと非常によく似た) Sass言語をサポートしている。
そのため、bootstrap-sassを追加することで、LESSをSassへ変換し、必要なBootstrapファイルを現在のアプリケーションですべて利用できるようにする。
source 'https://rubygems.org'
gem 'rails', '5.1.4'
gem 'bootstrap-sass', '3.3.7'
.
.
.
カスタムCSS
カスタムCSSにはすべてのページに適用される共通のスタイルを書き込む。
rails generateコマンドを実行することでコントローラーごとに分けられたCSSファイルが自動的に生成されるが、これらのファイルを正しい順序で読み込ませるのは至難の技なので、 (簡潔のために) すべてのCSSを1つにまとめる方針を採っている。
touch app/assets/stylesheets/custom.scss
カスタムCSS用のファイルを作成したら、@importを使って、Bootstrap (とそれに関連するSprockets) を読み込む。
@import "bootstrap-sprockets";
@import "bootstrap";
パーシャル
<%= render 'layouts/shim' %>
app/views/layouts/_shim.html.erbというファイルを探してその内容を評価し、結果をビューに挿入している。
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
</script>
<![endif]-->
ファイル名 _shim.html.erb の先頭にあるアンダースコアは、パーシャルで使う普遍的な命名規約であり、また、一目見ただけでディレクトリ中のすべてのパーシャルを識別することが可能になる。
アセットパイプライン
Asset Pipelineの最大のメリットの1つは、本番のアプリケーションで効率的になるように最適化されたアセットも自動的に生成されること。
アセットディレクトリ
静的ファイルを目的別に分類する、標準的な3つのディレクトリが使われている。
- app/assets: 現在のアプリケーション固有のアセット
- lib/assets: あなたの開発チームによって作成されたライブラリ用のアセット
- vendor/assets: サードパーティのアセット
マニフェストファイル
静的ファイル (アセット) を上記の場所へそれぞれ配置すれば、マニフェストファイルを使って、それらをどのように1つのファイルにまとめるのかをRailsに指示することができる。
なお、実際にアセットをまとめる処理を行うのはSprocketsというgem。
/*
* 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
*/
重要な部分は、実はCSSコメントの中にある。
コメント内の次の部分は、Sprocketsが適切なファイルを読み込むために使われている。
*= require_tree .
app/assets/stylesheetsディレクトリ (サブディレクトリを含む) 中のすべてのCSSファイルが、アプリケーションCSSに含まれるようにしている。
*= require_self
CSSの読み込みシーケンスの中で、application.css自身もその対象に含めている。
プリプロセッサエンジン
必要なアセットをディレクトリに配置してまとめた後、Railsはさまざまなプリプロセッサエンジンを介してそれらを実行し、ブラウザに配信できるようにそれらをマニフェストファイルを用いて結合し、サイトテンプレート用に準備する。
プリプロセッサエンジンは、繋げて実行する (chain) ことができる。
foobar.js.coffee
上の拡張子の場合、CoffeeScriptプロセッサ経由で実行される。
foobar.js.erb.coffee
上の拡張子の場合は、CoffeeScriptとERbの両方で実行される (コードは右から左へと実行されるので、この例ではCoffeeScriptが最初に実行される)。
Sass
Sass は、スタイルシートを記述するための言語であり、SCSSというフォーマットに対応している (.scssという拡張子はSCSSであることを表す)。
有効なCSSファイルは、すべてSCSSファイルとしても扱うことができ、既存の記法ルールを使っているプロジェクトにとっても互換性のある便利なフォーマットになっている。
ネスト
スタイルシート内に共通のパターンがある場合は、要素をネストさせることができる。
/* ネスト前 */
.center {
text-align: center;
}
.center h1 {
margin-bottom: 10px;
}
/* ネスト後 */
.center {
text-align: center;
h1 {
margin-bottom: 10px;
}
}
次のような場合、SCSSではアンパーサンド&を使ってネストすることができる。
/* ネスト前 */
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
color: #fff;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 9px;
font-weight: bold;
}
#logo:hover {
color: #fff;
text-decoration: none;
}
/* ネスト後 */
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
color: #fff;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 9px;
font-weight: bold;
&:hover {
color: #fff;
text-decoration: none;
}
}
変数
Sassでは、冗長なコードを削除し、より自由な表現を可能にするために、変数が定義できるようになっている。
$light-gray: #777;
.
.
.
h2 {
.
.
.
color: $light-gray;
}
.
.
.
footer {
.
.
.
color: $light-gray;
}
ルートURL
ルートURLを定義すると、root_pathやroot_urlといったメソッドを通してURLを参照することができる。
一般的な規約に従い、基本的には_path書式を使い、リダイレクトの場合のみ_url書式を使うようにする。
root_path -> '/'
root_url -> 'http://www.example.com/'
getルールを使うと、GETリクエストが /help に送信されたときにStaticPagesコントローラーのhelpアクションを呼び出してくれるようになる。また、ルートURLのときと同様に、help_pathやhelp_urlといった名前付きルートも使えるようになる。
# 変更前
get 'static_pages/help'
# getルールを使って定義する
get '/help', to: 'static_pages#help'
名前付きルート
# リンクを直接記述
<a href="/about">About</a>
# 名前付きルート
<%= link_to "About", about_path %>
上のようにすることでコードの意味がわかりやすくなり、about_pathの定義を変えればabout_pathが使われているすべてのURLを変更できるため、柔軟性が高まる。
ページ名 | URL | 名前付きルート |
---|---|---|
Home | / | root_path |
About | /about | about_path |
Help | /help | help_path |
Contact | /contact | contact_path |
Sign up | /signup | signup_path |
Log in | /login | login_path |
サイトリンクのルーティングとURLのマッピング
as:オプション
名前付きルートは、as:オプションを使って変更することができる。
get '/help', to: 'static_pages#help', as: 'helf'
統合テスト
統合テストを使うと、アプリケーションの動作を端から端まで (end-to-end) シミュレートしてテストすることができる。
統合テストの作成
rails generate integration_test site_layout
統合テストの例
- ルートURL (Homeページ) にGETリクエストを送る。
- 正しいページテンプレートが描画されているかどうか確かめる。
- Home、Help、About、Contactの各ページへのリンクが正しく動くか確かめる。
require 'test_helper'
class SiteLayoutTest < ActionDispatch::IntegrationTest
test "layout links" do
get root_path
assert_template 'static_pages/home' # Homeページが正しいビューを描画しているかどうか確かめる
assert_select "a[href=?]", root_path, count: 2 # 特定のリンクが存在するかどうかを、aタグとhref属性をオプションで指定して調べている
assert_select "a[href=?]", help_path
assert_select "a[href=?]", about_path
assert_select "a[href=?]", contact_path
end
end
assert_templateメソッド
Homeページが正しいビューを描画しているかどうか確かめる。
assert_template 'static_pages/home'
assert_selectメソッド
ここでは、assert_selectメソッドの高度なオプションを使っている (このメソッド自体は3章でも登場している)。
今回のケースでは、特定のリンクが存在するかどうかを、aタグとhref属性をオプションで指定して調べている。
assert_select "a[href=?]", about_path
上のコードでは、Railsは自動的にはてなマーク "?" をabout_pathに置換している (このとき "about_path" 内に特殊記号があればエスケープ処理されます)。これにより、次のようなHTMLがあるかどうかをチェックすることができる。
<a href="/about">...</a>
count
一方で、ルートURLへのリンクは2つある (1つはロゴに、もう1つはナビゲーションバーにあります)。このようなときは、以下のように書くことで、Homeページのリンクの個数も調べることもできる。
assert_select "a[href=?]", root_path, count: 2
様々なassert_select
assert_selectには色々な指定の仕方がある。
しかし、このメソッドで複雑なテストはしない方が良い。
今回のようなレイアウト内で頻繁に変更されるHTML要素 (リンクなど) をテストするぐらいに抑えておくとよい。
Code | マッチするHTML |
---|---|
assert_select "div" | <div>foobar</div> |
assert_select "div", "foobar" | <div>foobar</div> |
assert_select "div.nav" | <div class="nav">foobar</div> |
assert_select "div#profile" | <div id="profile">foobar</div> |
assert_select "div[name=yo]" | <div name="yo">hey</div> |
assert_select "a[href=?]", ’/’, count: 1 | <a href="/">foo</a> |
assert_select "a[href=?]", ’/’, text: "foo" | <a href="/">foo</a> |
assert_selectのいくつかの使用例
assert_equalメソッド
assert_equal <期待される値>, <実際の値>
内部では==演算子で期待される値と実際の値を比較し、正しいかどうかのテストをしている。
# assert_equal <期待される値>, <実際の値>
assert_equal full_title, 'Ruby on Rails Tutorial Sample App'
統合テスト実行
rails test:integration