0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

railsチュートリアルまとめ3 ほぼ静的なページの作成

0
Posted at

個人的リマインド用

参考
Ruby on Rails チュートリアル プロダクト開発の0→1を学ぼう

3 ほぼ静的なページの作成

※最初に注意点
rails newのとき--skip-bundleをすると、RailsでJSを利用する上で必要なパッケージのインストールもスキップする。(どんなパッケージかは後々8とかで出てくる)

gemインストールの際に

bundle _2.3.14_ config set --local without 'production'
上記のコマンドでproduction環境でしか使わないgemはインストールしないようにできる

例えばPostgreSQL用のpgというgemをdevelopment環境にインストールせず、
代わりにSQLiteがdevelopment環境とtest環境で使われるようになる。

一般的にはdevelopment環境とproduction環境は極力同じに保ち、環境ごとの違いを作らないようにするのが理想的。しかし、SQLiteの方がPostgreSQLよりもローカルでのインストールや設定がずっと楽なので、今回は異なるデータベースを使うことにする。

静的ページの作成

まずはStaticPages(キャメルケース)コントローラを作成。今回使うアクションはhome,help,aboutの3つ。学習のため、aboutは後々作成することに。
※コントローラ名をキャメルケースにするのは慣習。StaticPagesからstatic_pages_controllerが生成される。

rails g controller StaticPages home help
※コントローラー名は複数形!その後にアクション名を書けば自動で生成される。

豆知識

完全なコマンド 短縮系
rails server rails s
rails console rails c
rails generate rails g
rails test rails t
bundle install bundle

元に戻す方法
コントローラを生成した後にやり直したいとき。コントローラ以外にも大量のファイルが生成されるためただ消すだけでは足りない。そういうときはdestroyを使う。

rails generate controller StaticPages home help
rails destroy controller StaticPages home help

rails generate model User name:string email:string
rails destroy model User

マイグレーションの変更を元に戻したいとき

rails db:migrate
rails db:rollback 1つ前に戻したいとき
rails db:migrate VERSION=0 最初の状態に戻したいとき

routesファイルについて

controllerを作成した際にroutesファイルが変更されている。

config/routes.rb

Rails.application.routes.draw do
  get  "static_pages/home"
  get  "static_pages/help"
  root "application#hello"
end

get /static_pages/homeに注目
このルールは、/static_pages/homeというURLに対するリクエストを、StaticPagesコントローラのhomeアクションと結びつけている。今回はgetと書かれているから、HTTPリクエストのGETリクエストを受け取った時に対応するアクションを結びつけている。

GETやその他のHTTPメソッドについて
HTTPには4つの基本的な操作があり、それぞれGET,POST,PATCH,DELETEという4つの動詞に対応づけられている。

GETは最頻出のHTTPリクエストで、主にWeb上のデータを読み取る時に使われる。例えば、Webサイトを開く時とかにGETリクエストをサイトに送信する。

POSTは、ページ上のフォームに入力した値を、ブラウザから送信する時に使われる。何かを作成するとき、例えばユーザー登録フォームで新しいユーザーを作成する際にPOSTリクエストを送信する。

他にもPATCH更新の際、DELETE削除の際に使われる。これらは、ブラウザがネイティブには送信しないものである。しかしRailsなどのフレームワークは、ブラウザがこれらの操作のリクエストを送信しているかのように見せかける技術を駆使し、PATCHとDELETEという操作を実現している。

再び静的サイト制作に戻る

現在StaticPagesコントローラがどうなっているかというと

app/controllers/static_pages_controller.rb

class StaticPagesController < ApplicationController
  def home
  end

  def help
  end
end

こんな感じ。一般的なRESTアクションには対応していない。
このページはStaticPagesControllerというクラスを定義していることが分かる。このようなクラスはメソッドをまとめる時に便利。また、ApplicationControllerクラスを継承していることもわかる。

見ての通りメソッドは空で、通常のRubyならば何も動作しないが、特定のクラスを継承していることでRails特有の振る舞いをする。具体的には、/static_pages/homeというURLにアクセスすると、StaticPagesコントローラを参照し、homeアクションに記述されているコードを実行する。その後アクションに対応するビューを出力する。今回対応するビューはhome.html.erb

テスト入門

単語
テスト駆動開発(TDD): テストの手法の1つで、最初に「正しいコードがないと失敗するテスト」 を書き、次に本編のコードを書いてそのテストがパスするようにする

テストをいつ行えば良いのか
→まずはメリットのおさらい
1.テストが揃っていれば、機能停止に陥るような回帰バグ(Regression Bug: 以前のバグが再発したり機能の追加/変更に副作用が生じたりすること)を防止できる。

2.テストが揃っていれば、コードを安全にリファクタリング(機能を変更せずにコードを改善)できる。

3.テストコードは、アプリケーションコードから見ればクライアントとして動作するので、アプリケーションの設計やシステムの他の部分とのインターフェイスを決めるときにも役に立つ。

→いつやるか
・アプリケーションのコードよりも明らかにテストコードの方が短くシンプルになる(=簡単に書ける)のであれば、「先に」書く

・動作の仕様がまだ固まりきっていない場合、アプリケーションのコードを先に書き、期待する動作を「後で」書く

・セキュリティが重要な課題またはセキュリティ周りのエラーが発生した場合、テストを「先に」書く

・バグを見つけたら、そのバグを再現するテストを「先に」書き、回帰バグを防ぐ体制を整えてから修正に取りかかる

・すぐにまた変更しそうなコード(HTML構造の細部など)に対するテストは「後で」書く

・リファクタリングするときは「先に」テストを書く。特に、エラーを起こしそうなコードや止まってしまいそうなコードを集中的にテストする

主要なテストはコントローラテストモデルテスト統合テストの3つ。

テストに取り掛かる

手順としてはテストを書く→失敗することを確認→コードを書き換える。
rails g controllerをした際にテストファイルが作成されている。

test/controllers/static_pages_controller_test.rb

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

それぞれのテストでは、アクションをgetして正常に動作することを確認する。この確認は「アサーション」(assertion)と呼ばれる手法で行う。getはHomeページやHelpページがいわゆる「GETリクエストを受け付ける」普通のWebページであることを示している。その次の「response:success」は実際にはHTTPのステータスコード(ここでは200 OK)を表す。

つまり1つ目のテストは「Homeページのテスト。GETリクエストをhomeアクションに対して送信せよ。そうすれば、リクエストに対するレスポンスは[成功]になるはず」というもの。

続いてaboutページのテストと作成

test/controllers/static_pages_controller_test.rb

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

  test "should get about" do #←このテストを追加
    get static_pages_about_url
    assert_response :success
  end
end

当然失敗する。なぜ失敗したか。

1.AboutページへのURLが見つからない

config/routes.rb

Rails.application.routes.draw do
  get  "static_pages/home"
  get  "static_pages/help"
  get  "static_pages/about" #←これを追加
  root "application#hello"
end

この結果static_pages_about_urlというヘルパーが使えるようになるらしい。

2.StaticPagesコントローラにaboutアクションがない

app/controllers/static_pages_controller.rb

class StaticPagesController < ApplicationController

  def home
  end

  def help
  end

  def about #←これを追加
  end
end

3.テンプレート(ビュー)がない

touch app/views/static_pages/about.html.erb

ちょっとだけ動的なページの作成

今回はページごとにtitleを変える

ページ URL 基本タイトル 追加タイトル
Home /static_pages/home "Ruby on Rails Tutorial Sample App" "Home"
Help /static_pages/help "Ruby on Rails Tutorial Sample App" "Help"
About /static_pages/about "Ruby on Rails Tutorial Sample App" "About"

タイトルをテストする
今回使うテストメソッド
assert_select: 特定のHTMLタグが存在するかどうかをテストする。この種のアサーションメソッドは「セレクタ」と呼ばれることもある。

test/controllers/static_pages_controller_test.rb

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

一番上のテストを例にすると、

タグ内に、「Home | Ruby on Rails Tutorial Sample App」という文字列があるかどうかをチェックしている。

ただ単にhtml内にそれぞれ書き込めばテストはパスできるが、それだとDRY(Don't Repeat Yourself)原則に反する。そこで重複を取り除くテクニックの一つとして、ビューで「ERB」が使える。Railsのprovideというメソッドを使い対ロルをページごとに変更する。

app/views/static_pages/home.html.erb

<% 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>
<% provide(:title, "Home") %>

<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>

provide→メソッドの引数では、"Home"という文字列と、:titleというラベルを関連づけている。
yield→provideで渡された文字列を挿入。ページごとに"Home"の部分を書き換えれば、テストをパスできる。

さらによく見ると
3つのページで違うのはbodyの中身だけ。リファクタリングできそう。

どうやるかというと、application.html.erbに共通部分を書く。

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta charset="utf-8">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

body内のyieldは、各ページにそれぞれ内容が記述されている。
参考にhomeページを

app/views/static_pages/home.html.erb

<% 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>

ちなみに

<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag ... %>

この部分は、スタイルシートとJSをページ内にインクルードするためのもの。これらはアセットパイプラインの一部であり、クロスサイトスクリプティング攻撃を緩和する、コンテンツセキュリティポリシーを実装するcsp_meta_tagと、クロスサイトリクエストフォージェリー攻撃を緩和するcsrf_meta_tagも含む(????)

最後にルーティングの設定

ルートファイル(開いて最初に見えるファイル)をhomeページに変えておこう。

config/routes.rb

Rails.application.routes.draw do
  root "static_pages#home" ←追加
  get  "static_pages/home"
  get  "static_pages/help"
  get  "static_pages/about"
end

おまけ

ページの最後にテストの色を変えて見やすくする方法と、Guardでのテストの自動化の方法が書いてあります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?