Rails

Rails Tutorial 第三章 簡易まとめ (動的ページへの編集)

目標

Homeページ、Helpページ、Aboutページをそれぞれ編集し、最終的にページごとに異なるタイトルを表示することです。ここではビューのtitleタグの内容を変更

<ページ名> | Ruby on Rails Tutorial Sample App

フロウ

ページタイトルの簡単なテストを書き (red)
      ↓
3つのページにタイトルを追加し (green)
      ↓
レイアウトファイルを活用してコードの重複を解決します (REFACTOR)

テストを実装(RED)

アサーションメソッド

assert_select "title", "Home | Ruby on Rails Tutorial Sample App"

→titleタグ内に”Home | Ruby on Rails Tutorial Sample App”という文字列があるかどうかをチェック

このコードをそれぞれのアクションテストファイルに書き込む

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

テスト:RED

タイトルを追加(GREEN)

app/views/static_pages/home.html.erb
 <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>

現在のhtmlファイルに基本構造を持たせる

app/views/static_pages/home.html.erb
 <!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>

help、aboutページもそれぞれ編集。
テスト:GREEN

レイアウトと埋め込みRuby (Refactor)、「DRY」(Don’t Repeat Yourself)という原則

重複コードをまとめ、きれいでスマートを目指す

「Ruby on Rails Tutorial Sample App」という基本タイトルは、各テストで毎回同じ内容を書いてしまっています。そこで、setupという特別なメソッド (各テストが実行される直前で実行されるメソッド) を使って、この問題を解決したい

変数を利用

test/controllers/static_pages_controller_test.rb
 require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Home | #{@base_title}"
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
    assert_select "title", "Help | #{@base_title}"
  end

  test "should get about" do
    get static_pages_about_url
    assert_response :success
    assert_select "title", "About | #{@base_title}"
  end
end

テスト:GREEN

provideメソッドを活用する

・ページのタイトルがどれもほぼ同じ (完全にではないが)。そこで。。。

最初にコードを若干追加して、現在は「ほぼ」同じになっているページのタイトルを完全に同じにしておきます。この方が、コードの重複を一括で取り除けるからです。

重複を取り除くテクニックの1つとして、ビューで「埋め込みRuby」(Embedded Ruby) が使えます。Home、Help、Aboutページには可変要素があるので、Railsのprovideメソッドを使ってタイトルをページごとに変更します。試にhome.html.erbビューのコード内のタイトルに含まれている "Home" という文字を置き換えて、動作を確認してみましょう

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>

ERB(Enbedded RuBy)

はWebページに動的な要素を加えるときに使うテンプレートシステムです
上のコードでは「<% ... %>」という記法が使われており、その中からRailsのprovideメソッドを呼び出しています。メソッドの引数では、"Home"という文字列と:titleというラベルを関連付けています。そしてタイトルの部分では、上の記法と連携する「<%= ... %>」というよく似た記法を使い、その中でRubyのyieldメソッドを呼び出しています。このメソッドによって、テンプレートのその部分に実際のタイトルが挿入されます。

help,aboutもそれぞれ。

テスト:GREEN

HTMLの構造全体が各ページで重複しているのでapplication.html.erbにまとめる

タイトルの可変部分をERBを使って置き換えたので、現在それぞれのページは次のような構造になっています。

<% provide(:title, "The Title") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    Contents
  </body>
</html>

こうして見ると、HTMLの構造はtitleタグの内容も含めてどのページも完全に同じ。異なる点があるとすれば、bodyタグの内側のcontentsだけ。

一辺に変更をできる
application.html.erbに変更を与える

app/views/layouts/application.html.erb
 <!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>

<%= yield %>
このコードは、各ページの内容をレイアウトに挿入するためのものです。ここでは、このコードの詳細な動作を正確に理解することは重要ではありません。レイアウトを使う際に、/static_pages/homeにアクセスするとhome.html.erbの内容がHTMLに変換され、<%= yield %>の位置に挿入される、ということだけ理解しておけば問題ありません。

それぞれのビューの重複部分を削除
例)home

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>

↓↓↓

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>
app/views/static_pages/help.html.erb
 <% 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
 <% 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>

テスト:GREEN

ルーティング設定

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