# 3章 静的なページと自動化テストについて学んでいく   ## セットアップ 新しいRailsのプロジェクトをセットアップ ```ruby rails _5.1.6_ new sample_app ``` をして、アプリケーションを開発。   その後、 **gemfile** を編集し、 いつも通り、bundle install ```ruby bundle install --without production ```   その後、今まで通り、git、herokuにアップ。 その際、Railsのデフォルトページはheorku上でうまく表示できないため、今まで通り、 **HELLO, WORLD.** を表示してみる。 **app/controllers/application_controller.rb** ```ruby class ApplicationController < ActionController::Base protect_from_forgery with: :exception def hello render html: "HELLO, WORLD." end end ``` **config/routes.rb** ```ruby Rails.application.routes.draw do root 'application#hello' end ```   ## 演習 1.BitbucketがMarkdown記法のREADMEをHTMLとして正しく描画しているか、確認してみてください。 A.bitbucketで確認できた。   2.本番環境 (Heroku) のルートURLにアクセスして、デプロイが成功したかどうか確かめてみてください。 A.https://rails-sample-12-10.herokuapp.com/   ## 静的ページ Railsのアクションは、コントローラの中に置く。また、コントローラ内の各アクションは目的に沿って互いに関連した操作(作成や削除など)を行う。一言でまとめると、コントローラとは(基本的に動的な)Webページの集合を束ねるコンテナのことです。   静的なページを作成は初めに **コントローラ** の生成をする。その際はgenerateスクリプトを使う。 また、コントローラ名は **キャメルケース(頭文字を大文字)** で作成する。   続いて、Homeページ、Helpページに使うアクションもそれぞれ作成することにし、 **アクション名はすべて小文字** のhome、helpにします。generateスクリプトではアクション名をまとめて指定することもできるので、コマンドラインでHomeページとHelpページ用のアクションもまとめて生成できる。   ## コマンドの短縮 railsコマンドには短縮形がある。 |完全なコマンド|短縮形| |:--|:--| |rails server|rails s| |rails console|rails c| |rails generate|rails g| |rails destroy|rails d| |rails test|rails t| |bundle install|bundle|   ### Gitリポジトリに追加 ```ruby git add -A git commit -m "Add a Static Pages controller" git push -u origin static-pages ``` 一番下のコマンドでstatic-pagesトピックブランチをBitbucketにプッシュできる。 それ以降は、 ```ruby git push ``` それ以降はこのコマンドで **static-pages** トピックブランチにプッシュできる。   ### キャメルケース コントローラを作成する際はキャメルケースを慣習化されているが、実際はスネークケースのコントローラファイルが生成される。 例: **static_pages_controller.rb** これは、 **ganarate** スクリプトには、 **underscore** と呼ばれるキャメルケースをスネークケースにする変換するメソッドがあるため。   ## 元に戻す方法 生成したコードを戻す方法。 **コントローラ** ```ruby rails generate controller StaticPages home help rails destroy controller StaticPages home help ```   **モデル** ```ruby rails generate model User name:string email:string rails destroy model User ``` また、この際は`name:string email:string`がいらない。(モデル名以外の引数は不要)   **マイグレーション** ```ruby rails db:migrate rails db:rollback rails db:migrate VERSION=0 ``` 一つ前の状態に戻すのは **db:rollback** 最初の状態に戻したいとき **db:migrate VERSION=0**     ## コントローラ **StaticPages** コントローラを生成すると(config/routes.rb)ファイルが自動的に更新される。 **config/routes.rb** ```ruby Rails.application.routes.draw do get 'static_pages/home' get 'static_pages/help' root 'application#hello' end ``` 次にこのコードをルールを見ていく ```ruby get 'static_pages/home' ``` **/static_pages/home** というURLに対するリクエストを、StaticPagesコントローラのhomeアクションと結びつけている。 今回はgetと書かれているため、GETリクエストを受け取ったときに対応するアクションを結びつけている。 なお、ここでいうGETリクエストとは、HTTP(HyperText Transfer Protocol)が対応しているメソッドの1つ。   ## HTTPメソッド HTTP (HyperText Transfer Protocol) には4つの基本的な操作があり、それぞれ **GET、POST、PATCH、DELETE** という4つの動詞に対応づけられている。 **クライアント** (例えばFirefoxやSafariなどのWebブラウザ)と **サーバー** (ApacheやNginxなどのWebサーバー) は、上で述べた4つの基本操作を互いに認識できるようになっています**(ローカル環境でRailsアプリケーションを開発しているときは、クライアントとサーバーが同じコンピュータ上で動いていますが、一般的には、それぞれ別のコンピュータで動作している)** 。Railsを含む多くのWebフレームワークは、HTTPの各操作を発展させたRESTアーキテクチャの影響を受けている。   **GET** は最も頻繁に使われるHTTPリクエストで、主にWeb上のデータを読み取る **(get)** ときに使われます。 **「ページを取得する (get a page)」** という意味のとおり、ブラウザはhttp://www.google.com/やhttp://www.wikipedia.org/などのWebサイトを開くたびにGETリクエストをサイトに送信する。   **POST** は、GETの次によく使用されるリクエストで、ページ上のフォームに入力した値を、ブラウザから送信する時に使われる。例えばRailsアプリケーションでは、POSTリクエストは何かを作成するときによく使われる **(なお本来のHTTPでは、POSTを更新に使ってもよいとしている)** 。例えばユーザー登録フォームで新しいユーザーを作成するときは、POSTリクエストを送信する。   **PATCH** と **DELETE** という2つの操作があり、それぞれサーバー上の何かを更新したり削除したりするときに使われる。これら2つの操作は、GETやPOSTほどは使われない。これは、 **ブラウザがPATCHとDELETEをネイティブでは送信しない** からです。しかし、Ruby on Railsなどの多くのWebフレームワークは、ブラウザがこれらの操作のリクエストを送信しているかのように見せかける **技術(偽装)** を駆使して、PATCHとDELETEという操作を実現している。結果として、Railsはこの4つのHTTPリクエスト (GET・POST・PATCH・DELETE) を全てサポートできるようになっている。   今回の **StaticPagesコントローラ** にあるメソッドは、次のようにどちらも最初は **空** になっている。   **純粋なRuby言語であれば、これらのメソッドは何も実行しない。しかし、Railsでは動作が異なる。StaticPagesControllerはRubyのクラスだが、ApplicationControllerクラスを継承しているため、StaticPagesControllerのメソッドは (たとえ何も書かれていなくても) Rails特有の振る舞いする。**   具体的には、 **/static_pages/home** というURLにアクセスすると、RailsはStaticPagesコントローラを参照し、homeアクションに記述されているコードを実行する。その後、そのアクションに対応する **ビュー(MVCのV)** を出力します。今回の場合、homeアクションが空になっているので、/static_pages/homeにアクセスしても、単に対応するビューが出力されるだけ。では、ビューはどのように出力されるのだろうか。また、どのビューが表示されるか。   もう一度注意深く読んでみると、アクションとビューの関係について推測がつくが、 **homeアクションはhome.html.erb** というビューに対応ししている。   ## 演習 1.Fooというコントローラを生成し、その中にbarとbazアクションを追加してみてください。 A. ```ruby rails generate controller Foo bar baz ```   2.紹介したテクニックを駆使して、Fooコントローラとそれに関連するアクションを削除してみてください。 A. ```ruby rails destroy controller Foo bar baz ```   ## テストから始める 何らかの変更を行う際は、常に **「自動化テスト」** し、確認する習慣が必要。アプリケーションを開発しながらテストスイート(1つの テスト・ケースが正常に完了しないと次のテスト・ケースが開始しない ようなテスト作業において、ギャップを識別できる)を作成できれば、いざというときにのセーフティネットになる。テスト作成の習慣をできるだけ早いうちに身につけることが重要。   ### テストのメリット 1.テストが揃えば、バグを防止できる。   2.コードを安全にリファクタリング(機能を変更せずコードを改善すること)ができる。   3.テストはクライアントとして動作するので、アプリケーションの設計やシステムを決めるときにも役立つ。   ## 最初のテスト **`rails g controller`** を実行した時点でテストファイルが作成される。   **test/controllers/static_pages_controller_test.rb** ```ruby require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest test "should get home" do get static_pages_home_url assert_response :success end test "should get help" do get static_pages_help_url assert_response :success end end ``` このファイルにはテストが2つあり、アクションをgetして、正常に動作することを確認している。この確認は「アサーション」と呼ばれる手法。   ```ruby test "should get home" do get static_pages_home_url assert_response :success end ``` 言葉で表すと「Homeページのテスト。GETリクエストをhomeアクションに対して発行 (=送信) せよ。そうすれば、リクエストに対するレスポンスは[成功]になるはず」となっている。   テストの実行は以下のようにrailsコマンドを使う。 ```ruby rails test ``` 出力: 2 tests, 2 assertions, 0 failures, 0 errors, 0 skips 自分の場合: 2 runs, 2 assertions, 0 failures, 0 errors, 0 skips    ## Red テスト駆動開発のサイクルは「失敗するですとを最初に書く」→「次にアプリケーションのコードを書いて成功させる」→「必要ならリファクタリングする」のように進める。 多くのテストツールではテストの失敗を **RED** 、成功したときを **GREEN** で表す。このサイクルを **「RED・GREEN・REFACTOR」** と呼ぶこともある。   まずは、失敗するテストを書いてREDとなるようにする。 **test/controllers/static_pages_controller_test.rb** ```ruby test "should get about" do get static_pages_about_url assert_response :success end ``` を加えて **rails test** 当然ないので、エラー。 出力: 3 runs, 2 assertions, 0 failures, 1 errors, 0 skips   ## Green エラーメッセージは以下のようになっている。 **NameError: undefined local variable or method `static_pages_about_url'** 「AboutページへのURLが見つからない」といっている。   ルーティングファイルに追加。 **config/routes.rb** ```ruby get 'static_pages/about' ``` 追加したらもう一度テスト エラーメッセージは以下のようになっている **AbstractController::ActionNotFound: The action 'about' could not be found for StaticPagesController** StaticPagesコントローラにaboutアクションがない」といっている。   次にaboutアクションを追加 **app/controllers/static_pages_controller.rb** ```ruby def about end ``` 再度、rails test **ActionController::UnknownFormat: StaticPagesController#about is missing a template for this request format and variant.** テンプレートすなわち、ビューがないを言っているので、 **app/views/static_pages** に **sbout.html.erb** というファイルを追加。   ```ruby touch app/views/static_pages/about.html.erb ```   そして、htmlを整えて、再度、rails testすると **3 runs, 3 assertions, 0 failures, 0 errors, 0 skips** **GREEN** になる。   ## Refactor リファクタリング:機能を変更せずいコードを改善すること。 これをこまめに繰り返して、コードを常にすみずみまで美しくコンパクトに保ち、他の開発者や未来の自分の開発意欲を阻喪(そそう)することないようにしなければならない。   ## 少しだけ動的なページ ページのタイトルを自ら書き換えて表示するようにする。   ここでは学習のため **applecation.html.erb** を使わない。 ```ruby mv app/views/layouts/application.html.erb layout_file ```   ## タイトルをテストする(Red) **assert_select** メソッドを使い、特定のHTMLタグが存在するかどうかをテストする。この種のアサーションメソッドはその名から「セレクタ」を呼ばれる。 ```ruby assert_select "title", "Home | Ruby on Rails Tutorial Sample App" ``` 上のセレクタは、titleタグ内に、「Home | Ruby on Rails Tutorial Sample App」があるかチェックする。同じ要領で、3つのテストに書き足す。   **test/controllers/static_pages_controller_test.rb** ```ruby require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest test "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Home | Ruby on Rails Tutorial Sample App" end test "should get help" do get static_pages_help_url assert_response :success assert_select "title", "Help | Ruby on Rails Tutorial Sample App" end test "should get about" do get static_pages_about_url assert_response :success assert_select "title", "About | Ruby on Rails Tutorial Sample App" end end ```   当然、テストをするとREDになる。 **3 runs, 6 assertions, 3 failures, 0 errors, 0 skips**   ## タイトルを追加する(Green) 各ページにタイトルを追加して、テストがパスするようにする。 **app/views/static_pages/home.html.erb** ```html <!DOCTYPE html> <html> <head> <title>Home | Ruby on Rails Tutorial Sample App</title> </head> <body> <h1>Sample App</h1> <p> This is the home page for the <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a> sample application. </p> </body> </html> ```   **app/views/static_pages/help.html.erb** ```html <!DOCTYPE html> <html> <head> <title>Help | Ruby on Rails Tutorial Sample App</title> </head> <body> <h1>Help</h1> <p> Get help on the Ruby on Rails Tutorial at the <a href="https://railstutorial.jp/help">Rails Tutorial help page</a>. To get help on this sample app, see the <a href="https://railstutorial.jp/#ebook"> <em>Ruby on Rails Tutorial</em> book</a>. </p> </body> </html> ```   **app/views/static_pages/about.html.erb** ```html <!DOCTYPE html> <html> <head> <title>About | Ruby on Rails Tutorial Sample App</title> </head> <body> <h1>About</h1> <p> <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a> is a <a href="https://railstutorial.jp/#ebook">book</a> and <a href="https://railstutorial.jp/#screencast">screencast</a> to teach web development with <a href="http://rubyonrails.org/">Ruby on Rails</a>. This is the sample application for the tutorial. </p> </body> </html> ```   これで、テストは **GREEN** になる **3 tests, 6 assertions, 0 failures, 0 errors, 0 skips**   ## 演習 1.StaticPagesコントローラのテストには、いくつか繰り返しがあったことにお気づきでしょうか? 特に「Ruby on Rails Tutorial Sample App」という基本タイトルは、各テストで毎回同じ内容を書いてしまっています。そこで、setupという特別なメソッド (各テストが実行される直前で実行されるメソッド) を使って、この問題を解決したいと思います。まずは、green になることを確認してみてください。 A. 確認だけなので省略。   ## レイアウトと埋め込みRuby(Refactor) Railsの効力を十分に発揮できていない。 ・ページのタイトルがどれも同じ。 ・「Ruby on Rails Tutorial Sample App」という文字が3つのタイトルで繰り返し使われている。 ・HTMLの構造全体が各ページで重複している。   これは、Rubyの「DRY」(Don’t Repeat Yourself: 繰り返すべからず) という原則に反す。   重複を取り除くテクニックとして **「埋め込みRuby」(Embedded Ruby)** が使える。Railsの **provideメソッド** を使ってタイトルをページごとに変更する。   **app/views/static_pages/home.html.erb** ```html <% provide(:title, "Home") %> <!DOCTYPE html> <html> <head> <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title> </head> <body> <h1>Sample App</h1> <p> This is the home page for the <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a> sample application. </p> </body> </html> ``` ERBはWebページに動的な要素を加えるときに使うテンプレートシステム。   メソッドの引数では、"Home"という文字列と:titleというラベルを関連付けている。 そして、タイトル部分でprovideメソッドを連携する。Rubyの **yieldメソッド** を呼び出している。このメソッドによって、テンプレート部分に実際のタイトルが挿入される。   ## application.html.erb レイアウトをまとめる。 **app/views/layouts/application.html.erb** ```html <!DOCTYPE html> <html> <head> <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> </body> </html> ``` この中で注目すべきなのが、 ```html <%= yield %> ``` このコードは、各ページの内容をレイアウトに挿入するためのもの。 **application.html.erb** 以外のhtml.erbを変換し、yieldに挿入される感じ。   また、以下のコードが追加される。 ```html <%= csrf_meta_tags %> <%= stylesheet_link_tag ... %> <%= javascript_include_tag "application", ... %> ``` 上の3つのERBはスタイルシート、JavaScript、csrf_meta_tagsメソッドをページ内で展開するためのもの。スタイルシートとJavaScriptはAsset Piplineの一部。 csrf_meta_tagsは、Web攻撃手法の1つであるクロスサイトリクエストフォージェリーを防ぐために使われるRailsメソッド   **Asset Piplne** とは、 **「開発作業がしやすいようにファイルを分割してコーディングができるようにしつつ、最終的に一つのファイルに連結・圧縮する」仕組み** **CSRF** とは、一般ユーザに攻撃用Webページにアクセスするように誘導し、攻撃用Webページで用意した処理をさせること。 ![脆弱性攻撃](https://www.trendmicro.com/content/dam/trendmicro/global/ja/security-intelligence/research-reports/threat-solution/csrf/figure-csrf-20130903.png)   apllication.html.erbのおかげで、home,help,aboutは以下のようになる。   **app/views/static_pages/home.html.erb** ```html <% provide(:title, "Home") %> <h1>Sample App</h1> <p> This is the home page for the <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a> sample application. </p> ``` **app/views/static_pages/help.html.erb** ```html <% provide(:title, "Help") %> <h1>Help</h1> <p> Get help on the Ruby on Rails Tutorial at the <a href="https://railstutorial.jp/help">Rails Tutorial help section</a>. To get help on this sample app, see the <a href="https://railstutorial.jp/#ebook"><em>Ruby on Rails Tutorial</em> book</a>. </p> ``` **app/views/static_pages/about.html.erb** ```html <% provide(:title, "About") %> <h1>About</h1> <p> <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a> is a <a href="https://railstutorial.jp/#ebook">book</a> and <a href="https://railstutorial.jp/#screencast">screencast</a> to teach web development with <a href="http://rubyonrails.org/">Ruby on Rails</a>. This is the sample application for the tutorial. </p> ``` になる。   最後にテスト ```ruby rails test ``` **3 runs, 6 assertions, 0 failures, 0 errors, 0 skips**     ## 演習 1.コンタクトページを作成 A. まず、テスト **test/controllers/static_pages_controller_test.rb** ```ruby test "should get contact" do get static_pages_contact_url assert_response :success assert_select "title", "Contact | #{@base_title}" end ``` rails testにて **4 runs, 6 assertions, 0 failures, 1 errors, 0 skips** エラーが出る   次に、 **config/root.rb** にて ```ruby get 'static_pages/contact' ``` **app/controllers/static_pages_controller.rb** にて ```ruby def contact end ``` を追加。 最後にtouchコマンドでcontact.html.erbを作成。 **app/views/static_pages/contact.html.erb** ```html <% provide(:title, "Contact") %> <h1>Contact</h1> <p> Contact the Ruby on Rails Tutorial about the sample app at the <a href="https://railstutorial.jp/contact">contact page</a>. </p> ``` そしてテスト **4 runs, 8 assertions, 0 failures, 0 errors, 0 skips**   ## 演習 1.リスト 3.41にrootルーティングを追加したことで、root_urlというRailsヘルパーが使えるようになりました (以前、static_pages_home_urlが使えるようになったときと同じです)。リスト 3.42のFILL_INと記された部分を置き換えて、rootルーティングのテストを書いてみてください A. **test/controllers/static_pages_controller_test.rb** ```ruby test "should get root" do get root_url assert_response :success end ```   2.config/root.rbをコメントアウトしてREDにしろ A. 出来た。   ## デプロイ デプロイする前にテストを走らせているが、こういった習慣を身につけておくと開発に役立つ。   ## 高度なセットアップ minitest reportersとGuardのセットアップ masterブランチでする必要がある。   ### minitest reporters minitest-reporters gemを利用して、 **test/test_helper.rb** に以下を追加。 ```ruby require "minitest/reporters" Minitest::Reporters.use! ``` requireして、クラス変数をなんかしてる?   ### Guardによるテスト自動化 guard gemをいれ、初期化するだけ。 そして、 **Guardfile** を定義する。 ```ruby guard :minitest, spring: "bin/rails test", all_on_start: false do ``` この行では、GuardからSpringサーバーを使って読み込み時間を短縮している。   **Spinrgとは** :事前にバックグラウンドでライブラリをロードしておくことで、その待ち時間を短くするアプリケーションプリローダー。コマンドを素早く実行することができるらしい。   git と spring は競合するらしいので、gitignoreに登録すべき。   いろいろエラーがあったが、 ```ruby guard :minitest, spring: "rails test", all_on_start: false do watch(%r{^test/(.*)/?(.*)_test\.rb$}) ``` と修正したらできた。