3章ほぼ静的なページの作成
3.1 セットアップ
サンプルアプリケーションを作る
cd ~/environment rails _5.1.6_ new sample_app cd sample_app/
#Gemfileを編集する。 source 'https://rubygems.org' gem 'rails', '5.1.6' gem 'puma', '3.9.1' gem 'sass-rails', '5.0.6' gem 'uglifier', '3.2.0' gem 'coffee-rails', '4.2.2' gem 'jquery-rails', '4.3.1' gem 'turbolinks', '5.0.1' gem 'jbuilder', '2.7.0' group :development, :test do gem 'sqlite3', '1.3.13' gem 'byebug', '9.0.6', platform: :mri end group :development do gem 'web-console', '3.5.1' gem 'listen', '3.1.5' gem 'spring', '2.0.2' gem 'spring-watcher-listen', '2.0.1' end group :test do gem 'rails-controller-testing', '1.0.2' gem 'minitest', '5.10.3' gem 'minitest-reporters', '1.1.14' gem 'guard', '2.16.2' gem 'guard-minitest', '2.4.4' end group :production do gem 'pg', '0.20.0' end
bundle install --without production bundle update
hello
アクションをApplicationコントローラーに追加するapp/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def hello
render html: "hello, world!"
end
end
config/routes.rb
Rails.application.routes.draw do
root 'application#hello'
end
3.2静的なページ
git checkout -b static-pages #StaticPagesコントローラを生成する rails generate controller StaticPages home help
コントローラ名をキャメルケース (単語の頭文字を大文字にしてつなぎ合わせた名前) で渡していることに注目。こうすると、StaticPagesコントローラ名をスネークケース
(単語間にアンダースコアを加えて繋ぎ合わせた名前) にした
ファイルstatic_pages_controller.rbを自動的に生成するよ
短縮したコマンド一覧
#完全なコマンド #短縮形 rails server #rails s rails console #rails c rails generate #rails g rails test #rails t bundle install #bundle
home
アクションとhelp
アクションで使うルーティングconfig/routes.rb
Rails.application.routes.draw do
get 'static_pages/home'
get 'static_pages/help'
root 'application#hello'
end
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
end
def help
end
end
app/views/static_pages/home.html.erb
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
help
アクションに対応するビューも、上のコードと似ている。
app/views/static_pages/help.html.erb
<h1>StaticPages#help</h1>
<p>Find me in app/views/static_pages/help.html.erb</p>
演習
1:Foo
というコントローラを生成し、その中にbar
とbaz
アクションを追加してみてください。
rails g controller Foo bar baz
2:テクニックを駆使して、Foo
コントローラとそれに関連するアクションを削除してみてください。
rails destroy controller Foo bar baz
コントローラーの生成
自動生成と、それに対応する取り消し処理の例
rails generate controller StaticPages home help rails destroy controller StaticPages home help
モデルの自動生成についても、同様の方法で元に戻せるよ!
rails generate model User name:string email:string rails destroy model User
元に戻したいときは、db:rollbackで1つ前の状態に戻します。
rails db:migrate rails db:rollback
最初の状態に戻したいときは、VERSION=0オプションを使います。
rails db:migrate VERSION=0
0を別の数字に置き換えることによって、
指定したバージョンの状態に戻すことができます。
GETやその他のHTTPメソッドについて
クライアント (例えばFirefoxやSafariなどのWebブラウザ)とサーバー (ApacheやNginxなどのWebサーバー)は4つの基本操作(GET
、POST
、PATCH
、DELETE
)を互いに認識できるようになっています。
GETは最も頻繁に使われるHTTPリクエストで、ページを取得する
主にWeb上のデータを読み取る (get) ときに使われます。
POSTは、GETの次によく使用されるリクエストで、
ページ上のフォームに入力した値を、ブラウザから送信する時に使われます。
例えばRailsアプリケーションでは、POSTリクエストは何かを作成するときによく使われます(なお本来のHTTPでは、POSTを更新に使ってもよいとしている)。
例えばユーザー登録フォームで新しいユーザーを作成するときは、
POSTリクエストを送信します。
PATCHと DELETEという2つの操作があり、それぞれサーバー上の
何かを更新したり削除したりするときに使われます。
RESTとは、アプリケーションを構成するコンポーネント(Userなど)を、RDBMS(リレーショナルデータベースマネジメントシステム)のCRUD(Create/Read/Update/Delete)
・HTTPRequestの各メソッド(GET/POST/PUT/DELETE)
に対応させて、自由に作成/読み出し/更新/削除できるもの
HTTP Request URL アクション 用途 GET /users index すべてのユーザーを表示するページ GET /users/1 show id=1のユーザーを表示するページ GET /users/new new ユーザーを新規作成するページ POST /users create ユーザーを作成するアクション GET /users/1/edit edit id=1のユーザーを編集するページ PATCH /users/1 update id=1のユーザーを更新するアクション DELETE /users/1 destroy id=1のユーザーを削除するアクション (リソース)として扱うアーキテクチャ。
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>
app/views/static_pages/help.html.erb
<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>
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
end
def help
end
end
StaticPagesControllerというクラスを定義していることが分かります。このようなクラスは、メソッド (関数とも呼ばれます) をまとめるときに便利な手法です。
/static_pages/homeというURLにアクセスすると、
RailsはStaticPagesコントローラを参照し、
homeアクションに記述されているコードを実行します。
その後、そのアクションに対応するビュー (MVCのVに相当) を出力します。
今回の場合、homeアクションが空になっているので、/static_pages/homeにアクセスしても単に対応するビューが出力されるだけです。
プレースホルダ:place holderとは
正式な値が入るまで一時的に場所を確保しておく措置のことです。
3.3 テストから始める
テストスイートとは?
ソフトウェアプログラムが特定の動作を持っていることを示すために
ソフトウェアプログラムをテストするために使用することを目的とした
テストケースの集まりです。
テストケース:test caseとは?
どんな条件の元でどんなテストをするか洗い出してまとめたもの。
テストが揃っていれば、機能停止に陥るような回帰バグ
(Regression Bug: 以前のバグが再発したり機能の追加/
変更に副作用が生じたりすること) を防止できる。
テストが揃っていれば、コードを安全にリファクタリング
(機能を変更せずにコードを改善すること) ができる。
テストコードは、アプリケーションコードから見ればクライアントとして
動作するので、アプリケーションの設計やシステムの他の部分との
インターフェイスを決めるときにも役に立つ。
動的なページを作ろう!
ページ 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タグが存在するかどうかをテストします。
assert_select "title", "Home | Ruby on Rails Tutorial Sample App"
演習
1.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
タイトルにERBを使ったHomeページのビュー green
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>
タイトルにERBを使ったHelpページのビューgreen
app/views/static_pages/help.html.erb
<% provide(:title, "Help") %>
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | 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
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>
</body>
タイトルにERBを使ったAboutページのビュー green
app/views/static_pages/about.html.erb
<% provide(:title, "About") %>
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | 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>
<% provide(:title, "The Title") %> <!DOCTYPE html> <html> <head> <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title> </head> <body> Contents </body> </html>
テンプレート=Viewを指すよ
provideメソッドはcontent_forの代替
provideメソッドでパラメータを引き渡し
home.html.erb
<% provide(:title, “Home”) %>
yieldメソッドで受け取る
application.html.erb
<title><%= yield(:title) %></title>
<!– <title>Home</title> –>
provideメソッドを呼び出しています。メソッドの引数では、
“Home”という文字列と:titleというラベルを関連付けています
上の部分は重複しているので一つにまとめられる
演習
サンプルアプリケーションにContact (問い合わせ先) ページを作成してください
(/static_pages/contactというURLのページに「Contact | Ruby on Rails Tutorial Sample App」
というタイトルが存在するかどうかを確認するテストを最初に作成しましょう。
次に、Aboutページを作ったときのと同じように、Contactページにも
リストのコンテンツを表示してみましょう。
static_pages_controller_test.rb require 'test_helper' class StaticPagesControllerTest < ActionDispatch::IntegrationTest (中略) test "should get contact" do get static_pages_contact_url assert_response :success assert_select "title", "Contact | Ruby on Rails Tutorial Sample App" end end
ルーティング
routes.rb Rails.application.routes.draw do (中略) get 'static_pages/contact' end
コントローラーに”contact”アクション追加。
static_pages_controller.rb class StaticPagesController < ApplicationController (中略) def contact end end
Contactページ編集。
static_pages/contact.html.erb <% provide(:title, 'Contact') %> <h1>Contact</h1> <p> Contact the Ruby on Rails Tutorial about the sample app at the <a href="http://railstutorial.jp/contact">contact page</a>. </p>
演習
1:rootルーティングを追加したことで、root_urlというRailsヘルパー
が使えるようになりました (以前、static_pages_home_urlが使えるようになったときと同じです)。
リスト 3.42のFILL_INと記された部分を置き換えて、rootルーティングのテストを書いてみてください。
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 root" do get root_url assert_response :success end (中略) end
2:rootルーティングをコメントアウトして見て、 red になるかどうか確かめてみましょう。
最後に、コメントアウトした箇所を元に戻しテストが green になることを確認してみましょう。
routes.rb
#コメントアウトする Rails.application.routes.draw do #root 'application#hello' end
3.6.2 Guardによるテストの自動化
bundle exec guard init sudo yum install -y tmux # Cloud9を使っている場合に必要
Guardfile
# Guardのマッチング規則を定義 guard :minitest, spring: "bin/rails test", all_on_start: false do watch(%r{^test/(.*)/?(.*)_test\.rb$}) watch('test/test_helper.rb') { 'test' } watch('config/routes.rb') { integration_tests } watch(%r{^app/models/(.*?)\.rb$}) do |matches| "test/models/#{matches[1]}_test.rb" end watch(%r{^app/controllers/(.*?)_controller\.rb$}) do |matches| resource_tests(matches[1]) end watch(%r{^app/views/([^/]*?)/.*\.html\.erb$}) do |matches| ["test/controllers/#{matches[1]}_controller_test.rb"] + integration_tests(matches[1]) end watch(%r{^app/helpers/(.*?)_helper\.rb$}) do |matches| integration_tests(matches[1]) end watch('app/views/layouts/application.html.erb') do 'test/integration/site_layout_test.rb' end watch('app/helpers/sessions_helper.rb') do integration_tests << 'test/helpers/sessions_helper_test.rb' end watch('app/controllers/sessions_controller.rb') do ['test/controllers/sessions_controller_test.rb', 'test/integration/users_login_test.rb'] end watch('app/controllers/account_activations_controller.rb') do 'test/integration/users_signup_test.rb' end watch(%r{app/views/users/*}) do resource_tests('users') + ['test/integration/microposts_interface_test.rb'] end end # 与えられたリソースに対応する統合テストを返す def integration_tests(resource = :all) if resource == :all Dir["test/integration/*"] else Dir["test/integration/#{resource}_*.rb"] end end # 与えられたリソースに対応するコントローラのテストを返す def controller_test(resource) "test/controllers/#{resource}_controller_test.rb" end # 与えられたリソースに対応するすべてのテストを返す def resource_tests(resource) integration_tests(resource) << controller_test(resource) end
bundle exec guard
git add -A
git commit -m "Complete advanced setup"
3章のまとめ
-
新しいRailsアプリケーションを作成したのはこれで3度目。
今回も必要なgemのインストール、
リモートリポジトリへのプッュ、production環境まで行った。 -
コントローラを新規作成するためのrailsコマンドは
rails g controller ControllerName アクション名 (省略可)。
新しいルーティングはconfig/routes.rbファイルで定義する
Railsのビューでは、静的HTMLの他にERB (埋め込みRuby: Embedded RuBy) が使える。 -
常に自動化テストを使って新機能開発を進めることで、
自信を持ってリファクタリングできるようになり、回帰バグも素早くキャッチできるようになる。 -
テスト駆動開発では「red ・ green ・REFACTOR」サイクルを繰り返す
-
Railsのレイアウトでは、
アプリケーションのページの共通部分をテンプレートに
置くことでコードの重複を解決することができる。 -
コミット時に「マージするとSpringのプロセスID (pid) ファイルが上書きされる可能性があります」のようなエラーメッセージが表示される場合は、
コマンドラインでrm -f *.pidを実行してpidファイルを削除。 -
今はWebデザインで一般に使われるスタブ用の (とりあえずのダミーとして使われる)URL「’#’」を置いておきます。第3引数はオプションハッシュで、
この場合はサンプルアプリのリンクでCSS id logoを指定しています -
navタグには「その内側がナビゲーションリンクである」という意図を明示的に伝える役割があります。
-
alt属性は、画像がない場合に代わりに表示される文字列です