Rails Tutorial 第6版 学習まとめ 第5章

###概要
この記事は私の知識をより確実なものにするためにRailsチュートリアル解説記事を書くことで理解を深め
勉強の一環としています。稀にとんでもない内容や間違えた内容が書いてあるかもしれませんので
ご了承ください。
できればそれとなく教えてくれますと幸いです・・・

出典
[Railsチュートリアル第6版](https://railstutorial.jp/)

###この章でやること
以前作ったビューにスタイルが適用されていないのでBootstrapで整える。
パーシャルやAssetPipelineなどのビューまわりの機能などについても学習する。

###構造を追加する

CSSをあまり勉強していなくても簡単に洗練されたデザインを適用できるのがTwitter社が公開しているBootstrap
Bootstrapをうまく活用してスタイルを適用していく。

####ナビゲーション
要点となるコードをかいつまんで説明する。

・```[if It IE 9]```：条件付きコメントと呼ばれる。IEでサポートされている。今回はHTML5shimをIE9以下に読ませるために使用。

・```link_to "link_text", "URL"```：Railsヘルパーの一つ。リンクを作成する。URLには名前付きルートなども指定できる。

・<nav>タグは囲まれた部分がナビゲーションリンクであることをパッと見すぐわかるようにする役割。必須ではない。

・CSSクラスのcontainerやnavなどはBootstrapで特別な意味を持つ(Bootstrapスタイルを適用するのに必要。


#####演習
1.

```
$ curl -OL https://cdn.learnenough.com/kitten.jpg
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  138k  100  138k    0     0   194k      0 --:--:-- --:--:-- --:--:--  395k
```

2.```mv kitten.jpg app/assets/images/kitten.jpg```

3.```<%= image_tag("kitten.jpg", alt: "kitten") %>```をhome.html.erb最下行に追加

####BootstrapとカスタムCSS

Bootstrapはクラスを指定するだけで簡単にスタイルが適用できるという点も超便利だが
レスポンシブデザインに対応できるという点が便利すぎる。
通常ならブレイクポイントごとにそれぞれのサイズに合わせたスタイルを都度定義しなければならないが
Bootstrapならそれすら勝手にやってくれる。

SCSSというのはSassと呼ばれている。CSSを拡張した言語。スタイルの入れ子などCSSをより書きやすくしたもの。

CSSの読み方を少し解説。

```
body{

}
```
このように囲まれている場合は「body」タグに対してのスタイルが適用される。

```
.center{

}
```
このように.をつけた単語で囲まれる場合はCSSのcenterクラスに対してのスタイルが適用される。

```
#logo{

}
```
このように#をつけた場合はCSSのid logoに対してスタイルが適用される。

基本的なCSSセレクタはこんな感じ。

#####演習
1.Ctrl+/で選択した行が丸ごとコメントアウトされるので便利。未だにWindows環境で勉強しているのは突っ込まないでいただきたい。

2.imgタグをすべて非表示にするというCSSになる。

####パーシャル
アンダースコア_をファイル名先頭に置いたものはパーシャルとして扱う。
例>　_header.html.erbなど
パーシャルを使うことでレイアウトを見やすくしたり機能ごとのまとまりに分けることができて便利。

パーシャルはビューの中でrenderメソッドを使って読み込む。
renderで呼び出す際のファイル名にアンダースコアは含めない。

#####演習
1.<head>タグの部分を```<%= render 'layouts/head' %>```に置き換える。

2.renderメソッドで読み込むパーシャルを作成していないためTemplate::Errorとなる。

3.新規でhead.html.erbを作成しheadタグの内容をペーストする。

```erb:head.html.erb
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag    'application', media: 'all',
                               'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application',
                               'data-turbolinks-track': 'reload' %>
    <%= render 'layouts/shim' %>
  </head>
```

###Sassとアセットパイプライン

####アセットパイプライン

マニフェストファイルからアセットをどのようにまとめるかを指示できる。
アセットをまとめる処理はSprocketsというGemが行っている。

```*= require_tree .```という記述でツリー内のすべてのファイルをアプリケーションCSSにまとめるよう指定している。

SassやCoffeeScript(JavaScriptの拡張言語)、ERBなどのファイルはプリプロセッサエンジンを介して変換され
変換されたものがマニフェストファイルによって結合される。


アセットパイプラインを使うことで
・多数のファイルを一つにまとめる。
・余計な空白などを取り除きファイルサイズを最小化、最適化した状態で表示する。
こういった処理のおかげでブラウザでの読み込み時間削減などのメリットを受けられる。

####素晴らしい構文を備えたスタイルシート
Sass(SCSS)を使うとできること

・ネスト
普通なら別にセレクタを指定して書かなければならないものをネストして書くことができる。
つまり

```css
div{
  color: #eee;
}
div.container{
  width: 200px;
}
```
という記述を

```scss
div{
  color: #eee;
  .container{
    width: 200px;
  }
}
```
という風に入れ子にすることができる。
入れ子のし過ぎはNGだが適度に入れ子を使えばコーディングの手間を減らしたり構造を分かりやすくする効果がある。

・変数
CSSでの色コードなどの重複するような値を変数に保存することができる。
```$変数名: 値;```で変数を定義できる。


#####演習
1.[Railsチュートリアル第6版 リスト5.20](https://railstutorial.jp/chapters/filling_in_the_layout?version=6.0#code-refactored_scss)

###レイアウトのリンク
今のところ使える名前付きルート一覧

|ページ名|URL|名前付きルート|
|:--|:--|:--|
|Home|/|root_path|
|About|/about|about_path|
|Help|/help|help_path|
|Contact|/contact|contact_path|

[Railsチュートリアル第6章より](https://railstutorial.jp/chapters/filling_in_the_layout?version=6.0#table-url_mapping)

####Contactページ
第3章でいつの間にかやっていたので省略()
いちおうURLははっておく。→https://railstutorial.jp/chapters/filling_in_the_layout?version=6.0#sec-contact_page

####RailsのルートURL 
rootURLを定義することで/のルーティングを指定できるとともに
root_pathやroot_urlなどのヘルパーメソッドを使えるようになる。
これらはどちらもURLを返すメソッドで
root_path →相対パスを返す。　rootなので/
root_url  →絶対パスを返す。　rootなのでhttps://www.example.com/
相対パスか絶対パスかの違いでどっちを使っても基本的に問題はないが
Railsではリダイレクト時のリンク指定は絶対パスを使うという決まりがある。(一応相対パスでも大体は動く)
リダイレクト時は***_urlメソッド
それ以外では***_pathメソッドで指定しよう

homeページやhelpページなどはアプリの基本となるページなのでURLも最上位に置いておきたい
現在は/static_pages/helpとURLにstatic_pagesを挟んでいて少々面倒なので
/helpで飛べるように変更していく。

```ruby
  get '/help', to: 'static_pages#help'
  get '/about', to: 'static_pages#about'
  get '/contact', to: 'static_pages#contact'
```

このようにルーティングを書き換えることにより
help,about,contactの名前付きルートが設定され、/helpなどのURLがto:で指定されたルーティングに紐づけられるようになる。

ルーティングを変更するとテストで今まで使っていたメソッドが古くなってテストが通らなくなるので
一部修正する。

```ruby
  test "should get help" do
    get help_path
    assert_response :success
    assert_select "title", "Help | #{@base_title}"
  end
  
  test "should get about" do
    get about_path
    assert_response :success
    assert_select "title", "About | #{@base_title}"
  end
  
  test "should get contact" do
    get contact_path
    assert_response :success
    assert_select "title", "Contact | #{@base_title}"
  end
```

#####演習
1.2.ルーティングを更新したら
```get helf_path```とテストのメソッドを書き換える。
つまりasオプションで名前付きルートの名前を変えることができる。(デフォルトはURL)
helfというルートは/helpにアクセスした際、static_pagesコントローラのhelpアクションと結び付けられる。という意味

3.めんどくさいのでここもショートカットキーCtrl+Zを活用する。Macの方は調べてください…

####名前付きルート
名前付きルートを定義したので対応するヘルパーメソッドが使えるようになった
今までとりあえず#で代用していたリンク部分を名前付きルートで書き換えていく。

```<%= link_to "Contact", 'contact_path' %>```
こんな具合にヘッダー、フッターなどのリンクを書き換えていく。

#####演習
1.前の演習でhelfルートにしたまま戻すのを忘れていたのでそのままhelf_pathと定義すればいい。

2.前と同じく戻す際はCtrl+Zが便利(Windows民のみ)
ちなみにhelf_pathを使っている箇所はstatic_pages_controller_test.rbと_header.html.erbの2か所。
もちろん定義しているroutes.rbもhelfにするかhelpにするかで編集する。
これ以降helfは使わないのでhelpに戻しておこう。
1. routes.rbの```as: 'helf'```の記述を消す。
2. static_pages_controller_test.rbのhelf_pathをhelp_pathに変更
3. _header.html.erbのhelf_pathをhelp_pathに変更

####リンクのテスト
レイアウト内に存在するそれぞれのリンクが正しく動作をするか確かめるには手動でリンクを一つ一つ確かめる手もあるが
自動でテストしたほうが手間もないし、より確実。
今回の場合はstatic_pagesの各リンクをすべてチェックしたいので統合テストを書いていく。

今回追加した統合テストに書いたコードがこちら

```
  test "layout links" do
    get root_path
    assert_template 'static_pages/home'
    assert_select "a[href=?]",root_path, count: 2
    assert_select "a[href=?]",help_path
    assert_select "a[href=?]",about_path
    assert_select "a[href=?]",contact_path
  end
```
ルートパスにGETリクエストを送り、homeビューを表示したか確かめ、各リンクが存在するかどうか確かめている。

ここではassert_selectを少々高度に使っている。ように見えるが
第2引数にリンクのパスを入れるとそれが?の部分に代入されるだけである。
count: 2はその要素が2個あるかどうかを確かめているだけ。
分かれば単純なメソッド。

他にもいろいろな使い方ができる。
[assert_selectのいくつかの使用例(Railsチュートリアル第6版より)](https://railstutorial.jp/chapters/filling_in_the_layout?version=6.0#table-assert_select)

```rails test:integration```と指定することで統合テスト限定で実行できるが基本的にはguardの自動テストか
```rails t```で全てのテストを流してもそこまで実行時間に差はないので```rails t```でいいと思われる。

とここで私のテストがエラーをはいた

```
14:18:53 - INFO - Running: test/integration/site_layout_test.rb
Running via Spring preloader in process 10766
Started with run options --seed 5553

 FAIL["test_layout_links", #<Minitest::Reporters::Suite:0x000055eebbcd1e00 @name="SiteLayoutTest">, 1.4094162390028941]
 test_layout_links#SiteLayoutTest (1.41s)
        Expected exactly 2 elements matching "a[href="/"]", found 3..
        Expected: 2
          Actual: 3
        test/integration/site_layout_test.rb:7:in `block in <class:SiteLayoutTest>'

  1/1: [=====================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.41642s
1 tests, 2 assertions, 1 failures, 0 errors, 0 skips
```

どうやらテストコードで期待されているルートURLのリンクの数は2つに対し、実際には3つあるというらしい。
コードと実際のアプリの実行画面をのぞくと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617753/adab4da4-ae1b-1a97-317c-cf38e0ad83ba.png)

どうやら私が以前にやったscssの演習で

```
img{
  display: none;
}
```
をさぼって追加しなかったためリンクが3つになってしまっているらしい。
めんどくさいのでimage_tagの書いてある行を消したら治った()
このようにテストの実行結果で簡単に間違えている部分がわかるので
テストは適宜書くようにしよう…


#####演習
1.先ほどの例と似たもので

```
    Expected at least 1 element matching "a[href="/about"]", found 0..
    Expected 0 to be >= 1.
    test/integration/site_layout_test.rb:9:in `block in <class:SiteLayoutTest>'
```
/aboutへのパスが0だよ、1個以上あるはずだぞと怒られている。
これによってabout_pathの記述が抜けていることがわかる。

2.

```rb:application_helper_test.rb
require 'test_helper'
class ApplicationHelperTest < ActionView::TestCase
  test "full title helper" do
    assert_equal full_title, "Ruby on Rails Tutorial Sample App"
    assert_equal full_title("Help"), "Help | Ruby on Rails Tutorial Sample App"
  end
end
```

###ユーザー登録：最初のステップ
ユーザー登録ページを作り始める。
####Usersコントローラ
static_pagesの時と同じくrails generateコマンドでusersコントローラを作成する。
```$ rails g controller Users new```

#####演習
1. ```get '/signup', to: 'users#new'```このように書き換える。
2. エラーがいっぱい出てくる。ここに乗せるととんでもない量になるので省略。

####ユーザー登録用URL
先程の演習でエラーになった部分を修正する。
具体的には自動生成されたテストコードを/signupルーティングに対応させる。

```rb:users_controller_test.rb
  test "should get new" do
    get signup_path
    assert_response :success
  end
```
このようにsignup_pathに書き換えることでテストはパスする。

あとはhomeページのリンクにsignup_pathを適用し
自動生成されたsignupページを編集する。


#####演習
1.やってあるので省略
2.ルートを消したのでTemplateErrorやNameErrorが起きる。テスト画面は各自ご覧ください…
3．

```rb
    get signup_path
    assert_select "title", full_title("Sign up")
```
この2行をsite_layout_test.rbに追記する。

###最後に
いつも通りgitで今回の変更をコミットしてプッシュしておく。

[前の章へ](https://qiita.com/take_webengineer/items/265f29b77f3126d3a9df)

[次の章へ](https://qiita.com/take_webengineer/items/497fc90d7c6f9bc9a0ff)