## 前回の分からなかったこと
テスト駆動開発とは???
<u><a href="https://teratail.com/questions/121833" target="_blank">ここ</a></u>を見たが、まあ、経験を踏めばわかってくる概念であり、分かりにくいことが分かった。チュートリアルを通してもっと深く理解していきたい。
# 7章
## デバックとrails環境
サイトのレイアウトにデバック情報を追加する。
**app/views/layouts/application.html.erb**
```html
<%= debug(params) if Rails.env.development? %>
```
ビルトインのdebugメソッドとparams変数を使って、各プロフィールページにデバッグ用の情報が表示されるようにする。
**.development?** で、Railsの3つのデフォルト環境のうち、開発環境 (development) だけで表示されるようになる。
3つのデフォルト環境の使い分けについてだが、
・普段のrails consoleでは、
```bash
$ rails console
Loading development environment
>> Rails.env
=> "development"
>> Rails.env.development?
=> true
>> Rails.env.test?
=> false
```
development環境である。
・テスト環境のデバッグなど、他の環境でconsoleを実行する必要が生じた場合は、環境をパラメータ(変数)としてconsoleスクリプト(即座に実行できるプログラム)に渡すことができる。
```bash
$ rails console test
Loading test environment
>> Rails.env
=> "test"
>> Rails.env.test?
=> true
```
・Herokuは本番サイト用のプラットフォームなので、実行されるアプリケーションはすべて本番環境となる。
```bash
$ heroku run rails console
>> Rails.env
=> "production"
>> Rails.env.production?
=> true
```
詳しくは<u><a href="https://railstutorial.jp/chapters/sign_up?version=5.1#sec-rails_environments" target="_blank">コラム7.1</a></u>を見てください。
次にデバック表示を整形する。
**app/assets/stylesheets/custom.scss**
```scss
@import "bootstrap-sprockets";
@import "bootstrap";
/* mixins, variables, etc. */
$gray-medium-light: #eaeaea;
@mixin box_sizing {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.
.
.
/* miscellaneous */
.debug_dump {
clear: both;
float: left;
width: 100%;
margin-top: 45px;
@include box_sizing; /*定義したミックスイン*/
}
```
Sassのミックスインという機能が使われている。パッケージ化して、閣僚を減らす。見やすくする。
表示されたデバック出力には描画されたページの情報が含まれる。この **params** の内容は **YAML** という形式で書かれている。基本的にハッシュで、人間だけではなく、このコンピュータにとっても読みやすい形式。
## 演習
1.ブラウザから /about にアクセスし、デバッグ情報が表示されていることを確認してください。このページを表示するとき、どのコントローラとアクションが使われていたでしょうか? paramsの内容から確認してみましょう。
A.
デバック出力は以下のようになる。
```string
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
controller: static_pages
action: about
permitted: false
```
static_pagesコントローラのaboutアクションが使われたことが分かる。
2.Railsコンソールを開き、データベースから最初のユーザー情報を取得し、変数userに格納してください。その後、puts user.attributes.to_yamlを実行すると何が表示されますか? ここで表示された結果と、yメソッドを使ったy user.attributesの実行結果を比較してみましょう。
A.
まずは、findメソッドを使い、userに代入
```bash
user = User.find(1)
User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "Takukin", email: "mhartl@example.com", created_at: "2020-01-17 11:27:03", updated_at: "2020-01-18 05:35:38",
password_digest: "$2a$10$ZhxNCTARw/sPxesOSdbX2.1bQpTioIhOYk6WvXISOUO...">
```
次に、 **puts user.attributes.to_yaml**
```bash
---
id: 1
name: Takukin
email: mhartl@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
utc: &1 2020-01-17 11:27:03.438851000 Z
zone: &2 !ruby/object:ActiveSupport::TimeZone
name: Etc/UTC
time: *1
updated_at: !ruby/object:ActiveSupport::TimeWithZone
utc: &3 2020-01-18 05:35:38.851927000 Z
zone: *2
time: *3
password_digest: "$2a$10$ZhxNCTARw/sPxesOSdbX2.1bQpTioIhOYk6WvXISOUOYSD2o/l/5e"
=> nil
```
次に、 **y user.attributes**
```bash
---
id: 1
name: Takukin
email: mhartl@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
utc: &1 2020-01-17 11:27:03.438851000 Z
zone: &2 !ruby/object:ActiveSupport::TimeZone
name: Etc/UTC
time: *1
updated_at: !ruby/object:ActiveSupport::TimeWithZone
utc: &3 2020-01-18 05:35:38.851927000 Z
zone: *2
time: *3
password_digest: "$2a$10$ZhxNCTARw/sPxesOSdbX2.1bQpTioIhOYk6WvXISOUOYSD2o/l/5e"
=> nil
```
出力結果は、 **puts user.attributes.to_yamlとy user.attributesは一緒。**
## Userリソース
データの作成、表示、更新、削除をリソース(Resourceとして扱えるようにする。
**config/routes.rb**
```ruby
resources :users
```
これを **リソースルーティング** と呼ぶらしい。これを使うことによって、コントローラの **index、show、new、edit、create、update、destroyアクション** を個別に宣言しなくても1行で宣言が完了。これにより、今回の場合、 ***/users/1*** にアクセスできる。
しかし、
ルーティングテーブルは作れるが、ジェネレーターを使ってないので、アクションとビューは自分で作らなければならない。
まず、 **app/views/users/show.html.erb** にビューファイルを手動で作る。
**app/views/users/show.html.erb**
```html
<%= @user.name %>, <%= @user.email %>
```
次に、Userコントローラにshowアクションを定義。
**app/controllers/users_controller.rb**
```ruby
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
def new
end
end
```
これで、 ***/users/1*** にアクセスできる。
## 演習
1.埋め込みRubyを使って、マジックカラム (created_atとupdated_at) の値をshowページに表示してみましょう (リスト 7.4)。
A.
**app/views/users/show.html.erb**
```ruby
<%= @user.name %>, <%= @user.email %>, <%= @user.created_at %>, <%= @user.updated_at %>
```
のように、マジックカラム (created_atとupdated_at)を追加。
2.埋め込みRubyを使って、Time.nowの結果をshowページに表示してみましょう。ページを更新すると、その結果はどう変わっていますか? 確認してみてください。
A.
**app/views/users/show.html.erb**
```ruby
<%= @user.name %>, <%= @user.email %>, <%= @user.created_at %>, <%= @user.updated_at %>, <%= Time.now %>
```
のように、埋め込みRubyでTime.nowを追加。ブラウザを更新した時間が表示される。
## debuggerメソッド
もっと直接的にデバックする。 **byebug gemによるdebuggerメソッド**
使い方は直接debuggerをUserコントローラに差し込む。
**app/controllers/users_controller.rb**
```ruby
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
debugger
end
def new
end
end
```
そうして、ブラウザから /users/1 にアクセスし、Railsサーバーを立ち上げたターミナルを見て(byebug)というプロンプトがあれば成功。
ここで、Windows民はエラーを吐くので<u><a href="https://qiita.com/kusano_pg/items/eb38466f70dc05238fdb" target="_blank">ここで改善するとできるよ</a></u>gemのインストール。
(byebug)はRailsコンソールのようにコマンドを呼び出すことができて、アプリケーションのdebuggerが呼び出された瞬間の状態を確認することができる。
```bash
(byebug) @user.name
"Takukin"
(byebug) @user.email
"mhartl@example.com"
(byebug) params[:id]
"1"
```
Ctrl-Dを押すとプロンプトから抜け出すことができる。もう必要ないので消しておく。わからないことがあったらdebuggerを差し込んで、アプリケーション内のエラーを追跡したりデバッグするのがコツ。
## 演習
1.showアクションの中にdebuggerを差し込み (リスト 7.6)、ブラウザから /users/1 にアクセスしてみましょう。その後コンソールに移り、putsメソッドを使ってparamsハッシュの中身をYAML形式で表示してみましょう。ヒント: 7.1.1.1の演習を参考にしてください。その演習ではdebugメソッドで表示したデバッグ情報を、どのようにしてYAML形式で表示していたでしょうか?
A.
```bash
((byebug) puts params.to_yaml
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
controller: users
action: show
id: '1'
permitted: false
nil
```
2.newアクションの中にdebuggerを差し込み、/users/new にアクセスしてみましょう。@userの内容はどのようになっているでしょうか? 確認してみてください。
A.
**/app/controllers/users_controller.rb**
```ruby
def new
debugger
end
```
byebugにて
```bash
(byebug) @user
nil
```
となる。
## Gravatar画像とサイドバー
**Gravatarとは** :無料のサービスで、プロフィール写真をアップロードして、指定したメールアドレスと関連付けることができるもの。
まずはビューから
**app/views/users/show.html.erb**
```html
<% provide(:title, @user.name) %>
<h1>
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
```
次に、ヘルパーメソッドを定義する。ヘルパーファイルのどこでも定義できるが、分かりやすくするため、usersのヘルパーファイルにする。
**app/helpers/users_helper.rb**
```ruby
module UsersHelper
# 引数で与えられたユーザーのGravatar画像を返す
def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
```
gravatar_idの定義はuserのemailをハッシュ化してgravatarのURLで使えるようにし、gravatar_urlで画像を取ってくるイメージ??
alt属性を入れることでブラウザが読み上げてくれる。
デフォルトのメールアドレスをコンソール上で変え、デザインも整える。
**rails c**
```bash
$ rails console
>> user = User.first
>> user.update_attributes(name: "Example User",
?> email: "example@railstutorial.org",
?> password: "foobar",
?> password_confirmation: "foobar")
=> true
```
よって。ロゴが変わる。
デザインも変える。
**app/views/users/show.html.erb**
```html
<% provide(:title, @user.name) %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<h1>
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
</section>
</aside>
</div>
```
ここでてくる、 **rowやcol-md-4クラス** はbootstrapで定義されたクラス名。
CSSも追加。
**app/assets/stylesheets/custom.scss**
```css
/* sidebar */
aside {
section.user_info {
margin-top: 20px;
}
section {
padding: 10px 0;
margin-top: 20px;
&:first-child {
border: 0;
padding-top: 0;
}
span {
display: block;
margin-bottom: 3px;
line-height: 1;
}
h1 {
font-size: 1.4em;
text-align: left;
letter-spacing: -1px;
margin-bottom: 3px;
margin-top: 0px;
}
}
}
.gravatar {
float: left;
margin-right: 10px;
}
.gravatar_edit {
margin-top: 15px;
}
```
## 演習
1,(任意) Gravatar上にアカウントを作成し、あなたのメールアドレスと適当な画像を紐付けてみてください。メールアドレスをMD5ハッシュ化して、紐付けた画像がちゃんと表示されるかどうか試してみましょう。
A.
<u><a href="https://ja.gravatar.com/" target="_blank">Gravatar</a></u>にて、アカウントを作り、プロフィール画像を設定して、rails console上でサンプルデータ(User.first)のメールアドレスを登録したアドレスに変更したらできた。
2.7.1.4で定義したgravatar_forヘルパーをリスト 7.12のように変更して、sizeをオプション引数として受け取れるようにしてみましょう。うまく変更できると、gravatar_for user, size: 50といった呼び出し方ができるようになります。重要: この改善したヘルパーは10.3.1で実際に使います。忘れずに実装しておきましょう。
A.
コピペ。
3.オプション引数は今でもRubyコミュニティで一般的に使われていますが、Ruby 2.0から導入された新機能「キーワード引数 (Keyword Arguments)」でも実現することができます。先ほど変更したリスト 7.12を、リスト 7.13のように置き換えてもうまく動くことを確認してみましょう。この2つの実装方法はどういった違いがあるのでしょうか? 考えてみてください。
A.
コピペ。
## ユーザ登録フォーム
## form_forを使用する
**form_for** :ヘルパーメソッド。Active Recordのオブジェクトを取り込み、そのオブジェクトの属性を使ってフォームを構築する。
まずは、newアクションに@user変数を追加。
**app/controllers/users_controller.rb**
```ruby
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
end
```
次に、HTML、CSSの変更。
**app/views/users/new.html.erb**
```html
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(@user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
```
CSSに追加。
**app/assets/stylesheets/custom.scss**
```css
/* forms */
input, textarea, select, .uneditable-input {
border: 1px solid #bbb;
width: 100%;
margin-bottom: 15px;
@include box_sizing;
}
input {
height: auto !important;
}
```
開設は次のトピックでやるらしい。
## 演習
1.試しに、リスト 7.15にある:nameを:nomeに置き換えてみましょう。どんなエラーメッセージが表示されるようになりますか?
A.
**NoMethodError in Users#new**
**undefined method `nome'**
2.試しに、ブロックの変数fをすべてfoobarに置き換えてみて、結果が変わらないことを確認してみてください。確かに結果は変わりませんが、変数名をfoobarとするのはあまり良い変更ではなさそうですね。その理由について考えてみてください。
A.
結果は変わらない。
メタ構文変数(意味を持たない名前)として認識されるため、日本語では「ほにゃらら」などの意味で、変数名としてふさわしくないため。
## フォームHTML
前のHTMLの設定
**app/views/users/new.html.erb**
```html
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(@user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
```
は、ブラウザで以下のように置換される。
```html
<form accept-charset="UTF-8" action="/users" class="new_user"
id="new_user" method="post">
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden"
value="NNb6+J/j46LcrgYUC60wQ2titMuJQ5lLqyAbnbAUkdo=" />
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="email" />
<label for="user_password">Password</label>
<input id="user_password" name="user[password]"
type="password" />
<label for="user_password_confirmation">Confirmation</label>
<input id="user_password_confirmation"
name="user[password_confirmation]" type="password" />
<input class="btn btn-primary" name="commit" type="submit"
value="Create my account" />
</form>
```
変換された後に以下のコードが加えられている。
```ruby
<input name="utf8" type="hidden" value="✓" />
<input name="authenticity_token" type="hidden"
value="NNb6+J/j46LcrgYUC60wQ2titMuJQ5lLqyAbnbAUkdo=" />
```
このコードは、正しい文字コードを送信できたり、攻撃阻止するために信頼できるトークンを含めたりしている。
このように埋め込みRubyで超便利にコードが書ける。また、セキュリティのコードも生成してくれる。
## 演習
1.Learn Enough HTML to Be DangerousではHTMLをすべて手動で書き起こしていますが、なぜformタグを使わなかったのでしょうか? 理由を考えてみてください。
A.
formタグってのは入力・送信フォームを作成する時に使うタグでであり、
Learn Enough HTML to Be Dangerousの中では入力・送信フォームを作成していないから。
単純に扱っていない。
## ユーザ登録失敗
エラー一覧を表示する。
## 正しいフォーム
まずは、ユーザ登録の失敗に対応できるcreateアクションを追加。
**app/controllers/users_controller.rb**
```ruby
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(params[:user]) # 実装は終わっていないことに注意!
if @user.save
# 保存の成功をここで扱う。
else
render 'new'
end
end
end
```
ここで定義した
**@user = User.new(params[:user])** は、
```bash
@user = User.new(name: "Foo Bar", email: "foo@invalid",
password: "foo", password_confirmation: "bar")
```
と同じ意味になる。
しかしこれでは、脆弱性がある。
## Strong Parameters
paramsハッシュ全体を初期化するのはセキュリティ的に問題が発生する。
解決法
**app/controllers/users_controller.rb**
```ruby
def create
@user = User.new(user_params)
if @user.save
# 保存の成功をここで扱う。
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
```
このように、 **private** キーワードというものを使って、外部から使えないメソッドを定義し、@userに代入する仕組み。
これで解決
## 演習
1./signup?admin=1 にアクセスし、paramsの中にadmin属性が含まれていることをデバッグ情報から確認してみましょう。
A.
**http://localhost:3000//signup?admin=1**
```bash
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
admin: '1'
controller: users
action: new
permitted: false
```
## エラーメッセージ
エラーメッセージのパーシャルを作っていく。
まず、 **app/views/users/new.html.erb** にrenderとか、boot-strapが機能するように クラス名も定義していく。
**app/views/users/new.html.erb**
```ruby
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_for(@user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
<%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>
</div>
</div>
```
次に、パーシャルを作る。今回はディレクトリも生成する。
```bash
$ mkdir app/views/shared
$ touch app/views/shared/_error_messages.html.erb
```
**app/views/shared/_error_messages.html.erb**
```html
<% if @user.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(@user.errors.count, "error") %>.
</div>
<ul>
<% @user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
```
**any?** メソッドは、エラーが一つでもあれば発動する。empty?の逆。
**pluralize** は、第一引数によって、単数形か複数形にいてくれる。
また、CSSも追加する。
**app/assets/stylesheets/custom.scss**
```css
#error_explanation {
color: red;
ul {
color: red;
margin: 0 0 30px 0;
}
}
.field_with_errors {
@extend .has-error;
.form-control {
color: $state-danger-text;
}
}
```
ここでは、
Sassの@extend関数を使ってBootstrapのhas-errorというCSSクラスを適用している。
ここについて調べる。
## 演習
1.最小文字数を5に変更すると、エラーメッセージも自動的に更新されることを確かめてみましょう。
A.
**app/models/user.rb**
```ruby
validates :password, presence: true, length: { minimum: 5 }
```
にする。エラーメッセージも5になる。
2.未送信のユーザー登録フォーム (図 7.12) のURLと、送信済みのユーザー登録フォーム (図 7.18) のURLを比べてみましょう。なぜURLは違っているのでしょうか? 考えてみてください。
A.
ここ自信がないが、 **app/views/users/new.html.erb** をブラウザに変更しtら時、formタグのアクションが **"/users"** となるため。
```html
<form accept-charset="UTF-8" action="/users" class="new_user"
id="new_user" method="post">
```
## 失敗時のテスト
統合テストを生成して、登録フォームをテストする。
まず、統合テストを生成する。
```bash
rails generate integration_test users_signup
```
そこに、無効なデータを入れたとき、ユーザの数が変わらないかどうか、つまり変なデータができないかどうかのテスト
**test/integration/users_signup_test.rb**
```ruby
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: "",
email: "user@invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
end
end
```
テストはGREENになる。
## 演習
1.リスト 7.20で実装したエラーメッセージに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.25にテンプレートを用意しておいたので、参考にしてください。
A.
**test/integration/users_signup_test.rb**
```ruby
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: "",
email: "user@invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
assert_select 'div#error_explanation'
assert_select 'div.alert'
end
end
```
CSSのクラス、idについてのテストを書いた。
2.ユーザー登録フォームのURLは /signup ですが、無効なユーザー登録データを送付するとURLが /users に変わってしまいます。これはリスト 5.43で追加した名前付きルート (/signup) と、RESTfulなルーティング (リスト 7.3) のデフォルト設定との差異によって生じた結果です。リスト 7.26とリスト 7.27の内容を参考に、この問題を解決してみてください。うまくいけばどちらのURLも /signup になるはずです。あれ、でもテストは greenのままになっていますね...、なぜでしょうか? (考えてみてください)
A.
それぞれをコピペする。テストでは、ユーザ登録数の差異で判断してるから?
3.リスト 7.25のpost部分を変更して、先ほどの演習課題で作った新しいURL (/signup) に合わせてみましょう。また、テストが greenのままになっている点も確認してください。
A.
**test/integration/users_signup_test.rb**
```ruby
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post signup_path, params: { user: { name: "",
email: "user@invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
assert_select 'div#error_explanation'
assert_select 'div.alert'
end
end
```
4.リスト 7.27のフォームを以前の状態 (リスト 7.20) に戻してみて、テストがやはり greenになっていることを確認してください。これは問題です! なぜなら、現在postが送信されているURLは正しくないのですから。assert_selectを使ったテストをリスト 7.25に追加し、このバグを検知できるようにしてみましょう (テストを追加して redになれば成功です)。その後、変更後のフォーム (リスト 7.27) に戻してみて、テストが green になることを確認してみましょう。ヒント: フォームから送信してテストするのではなく、'form[action="/signup"]'という部分が存在するかどうかに着目してテストしてみましょう。
A.
コピペし、統合テストに以下を追加。
**est/integration/users_signup_test.rb**
```ruby
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post signup_path, params: { user: { name: "",
email: "user@invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
assert_select 'div#error_explanation'
assert_select 'div.alert'
assert_select 'form[action="/signup"]'
end
end
```
アクションが存在しないのでREDになる。
## ユーザー登録成功
Railsではcreateアクションに対応するビューがないため、慣習的にリダイレクトするようにしている。
**app/controllers/users_controller.rb**
```ruby
class UsersController < ApplicationController
.
.
.
def create
@user = User.new(user_params)
if @user.save
redirect_to @user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
```
このようになる。
ここでのリダイレクトコードは
```ruby
redirect_to user_url(@user)
```
これと同じ意味で、これの方が分かりやすいが省略された。
## 演習
1.有効な情報を送信し、ユーザーが実際に作成されたことを、Railsコンソールを使って確認してみましょう。
A.
signupしてrails cで確認したらできていた。
2.リスト 7.28を更新し、redirect_to user_url(@user)とredirect_to @userが同じ結果になることを確認してみましょう。
A.
省略。
## flash
フラッシュメッセージを追加していく。
**app/controllers/users_controller.rb**
```ruby
class UsersController < ApplicationController
.
.
.
def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
```
次に、レイアウトにflashを追加。
**app/views/layouts/application.html.erb**
```ruby
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
```
## 演習
1.コンソールに移り、文字列内の式展開 (4.2.2) でシンボルを呼び出してみましょう。例えば"#{:success}"といったコードを実行すると、どんな値が返ってきますか? 確認してみてください。
A.
rails cにて
```bash
puts "#{:success}"
success
```
2.先ほどの演習で試した結果を参考に、リスト 7.30のflashはどのような結果になるか考えてみてください。
A.
rails cにて
```bash
"#{flash[:success]}"
=> "It worked!"
```
## 実際にユーザ登録
実際に登録してみる。その際、データベースを一旦リセットする。
```bash
rails db:migrate:reset
```
また、サーバも再起動させる。
## 演習
1.Railsコンソールを使って、新しいユーザーが本当に作成されたのかもう一度チェックしてみましょう。結果は、リスト 7.32のようになるはずです。
A.
省略
2.自分のメールアドレスでユーザー登録を試してみましょう。既にGravatarに登録している場合、適切な画像が表示されているか確認してみてください。
A.
省略
## 成功時のテスト
ユーザが登録成功したときの統合テストを書く。
以下のようになる。
**test/integration/users_signup_test.rb**
```ruby
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
.
.
.
test "valid signup information" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { user: { name: "Example User",
email: "user@example.com",
password: "password",
password_confirmation: "password" } }
end
follow_redirect!
assert_template 'users/show'
end
end
```
ここでは、User.countでユーザの数を比較しながら、 follow_redirect!でしっかり'users/show'へ移動できたかをテストしている。
## 演習
1.7.4.2で実装したflashに対するテストを書いてみてください。どのくらい細かくテストするかはお任せします。リスト 7.34に最小限のテンプレートを用意しておいたので、参考にしてください (FILL_INの部分を適切なコードに置き換えると完成します)。ちなみに、テキストに対するテストは壊れやすいです。文量の少ないflashのキーであっても、それは同じです。筆者の場合、flashが空でないかをテストするだけの場合が多いです。
A.
**test/integration/users_signup_test.rb**
```ruby
assert_not flash.empty?
```
を追加。
2.本文中でも指摘しましたが、flash用のHTML (リスト 7.31) は読みにくいです。より読みやすくしたリスト 7.35のコードに変更してみましょう。変更が終わったらテストスイートを実行し、正常に動作することを確認してください。なお、このコードでは、Railsのcontent_tagというヘルパーを使っています。
A.
コピペ
3.リスト 7.28のリダイレクトの行をコメントアウトすると、テストが失敗することを確認してみましょう。
A.
省略。
4.リスト 7.28で、@user.saveの部分をfalseに置き換えたとしましょう (バグを埋め込んでしまったと仮定してください)。このとき、assert_differenceのテストではどのようにしてこのバグを検知するでしょうか? テストコードを追って考えてみてください
A.
リダイレクトした際に、本当ならば、ユーザが登録され、User.countが増えるはずなのにできていないから、REDになる。
## プロのデプロイ
まずは、マージしてmasterブランチに移動する。
## 本番環境でのSSL
Secure Sockets Layer(SSL)を使うことによって、ローカルのサーバからネットワークに流れる前に、大事な情報を暗号化してくれる。
本番環境用の設定ファイルであるproduction.rbのコードをたった1行変更するだけでSSLを強制し、httpsによる安全な通信を確立できる。
**config/environments/production.rb**
```ruby
Rails.application.configure do
.
.
.
# Force all access to the app over SSL, use Strict-Transport-Security,
# and use secure cookies.
config.force_ssl = true
.
.
.
end
```
## 本番環境用のWebサーバー
**config/puma.rb**
```ruby
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
threads threads_count, threads_count
preload_app!
rackup DefaultRackup
port ENV['PORT'] || 3000
environment ENV['RACK_ENV'] || 'development'
on_worker_boot do
# Worker specific setup for Rails 4.1+
# See: https://devcenter.heroku.com/articles/
# deploying-rails-applications-with-the-puma-web-server#on-worker-boot
ActiveRecord::Base.establish_connection
end
```
中身は理解しなくて良いらしい。
次に、 Pumaが使うようにProcfileで定義する。また、ルートディレクトリに作成。
**./Procfile**
```ruby
web: bundle exec puma -C config/puma.rb
```
## 本番環境へデプロイ
## 演習
1.ブラウザから本番環境 (Heroku) にアクセスし、SSLの鍵マークがかかっているか、URLがhttpsになっているかどうかを確認してみましょう。
A.
省略。
2.本番環境でユーザーを作成してみましょう。Gravatarの画像は正しく表示されているでしょうか?
A.
省略。