チュートリアル7章

第7章
ユーザー登録

Webサイトのレイアウトにデバッグ情報を追加

```ruby:app/views/layouts/application.html.erb
 <!DOCTYPE html>
<html>
  .
  .
  .
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
      <%= render 'layouts/footer' %>
      <%= debug(params) if Rails.env.development? %>　←ここ
    </div>
  </body>
</html>
```
デバッグ表示を整形するための追加と、Sassのミックスイン（CSSルールのグループをパッケージ化して複数の要素に適用することができます）

```ruby:app/assets/stylesheets/custom.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;
}
```

データの作成、表示、更新、削除をリソース (Resources) として扱う
HTTP標準には、これらに対応する４つの基本操作 (POST、GET、PATCH、DELETE) が定義されている

```ruby:config/routes.rb
 Rails.application.routes.draw do
  root 'static_pages#home'
  get  '/help',    to: 'static_pages#help'
  get  '/about',   to: 'static_pages#about'
  get  '/contact', to: 'static_pages#contact'
  get  '/signup',  to: 'users#new'
  resources :users　←ここ
end
```
```ruby:
GET	/users	index	users_path	すべてのユーザーを一覧するページ
GET	/users/1	show	user_path(user)	特定のユーザーを表示するページ
GET	/users/new	new	new_user_path	ユーザーを新規作成するページ (ユーザー登録)
POST	/users	create	users_path	ユーザーを作成するアクション
GET	/users/1/edit	edit	edit_user_path(user)	id=1のユーザーを編集するページ
PATCH	/users/1	update	user_path(user)	ユーザーを更新するアクション
DELETE	/users/1	destroy	user_path(user)	ユーザーを削除するアクション
```
html.erbファイルは手動で作成する必要があります

```ruby:ubuntu
touch　app/views/users/show.html.erb
```
```ruby:app/views/users/show.html.erb
 <%= @user.name %>, <%= @user.email %>
```
```ruby:app/controllers/users_controller.rb
 class UsersController < ApplicationController

  def show
    @user = User.find(params[:id])
  end

```
Usersコントローラにリクエストが正常に送信されると、params[:id]の部分はユーザーidの1に置き換わります

ユーザーのビューとアクションが定義されたので、/users/1 は完全に動作するようになりました

Gravatarは無料のサービスで、プロフィール写真をアップロードして、指定したメールアドレスと関連付けることができます。

```ruby:app/views/users/show.html.erb
 <% provide(:title, @user.name) %>
<h1>
  <%= gravatar_for @user %>
  <%= @user.name %>
</h1>
```
GravatarのURLはユーザーのメールアドレスをMD5という仕組みでハッシュ化しています。

```ruby:app/helpers/users_helper.rb
 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
```

ユーザーのサイドバーの最初のバージョンを作りましょう



```ruby:app/views/users/show.html.erb
 <% 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>
```

```ruby:app/assets/stylesheets/custom.scss
 .
.
.
/* 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;
}
```
ユーザー登録に欠かせないform_forヘルパーメソッドを使います

```ruby:app/controllers/users_controller.rb
 class UsersController < ApplicationController

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new ←ここ
  end
end
```
```ruby:app/views/users/new.html.erb
 <% 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>
```
```ruby:app/assets/stylesheets/custom.scss
 .
.
.
/* forms */

input, textarea, select, .uneditable-input {
  border: 1px solid #bbb;
  width: 100%;
  margin-bottom: 15px;
  @include box_sizing;
}

input {
  height: auto !important;
}
```

ユーザ登録の失敗

```ruby:app/controllers/users_controller.rb
・
・
・
def create
    @user = User.new(params[:user])    # 実装は終わっていないことに注意!
    if @user.save
      # 保存の成功をここで扱う。
    else
      render 'new'
    end
  end
end
```

Strong Parameters
params[:user]⇒user_params
許可された属性のみが含まれたparamsのハッシュです (:user属性がない場合はエラーになります)。

これらのパラメータを使いやすくするために、user_paramsという外部メソッドを使うのが慣習になっています。このメソッドは適切に初期化したハッシュを返し、params[:user]の代わりとして使われます。

```ruby:app/controllers/users_controller.rb
 class UsersController < ApplicationController
  .
  .
  .
  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
end
```
登録に失敗した場合のエラーメッセージ

form-controlというCSSクラスも一緒に追加することで、Bootstrapがうまく取り扱ってくれる

```ruby:app/views/users/new.html.erb
 <% 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>
```
複数のビューで使われるパーシャルは専用のディレクトリ「shared」によく置かれます (実際このパーシャルは10.1.1でも使います)。ただし、今はまだapp/views/sharedといったディレクトリは作っていないので、mkdirコマンドを使い、新しくディレクトリを作成する必要があります。

```ruby:
$ mkdir app/views/shared
$touch　app/views/shared/_error_messages.html.erb
```
```ruby:app/views/shared/_error_messages.html.erb
 <% 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 %>
```
```ruby:app/assets/stylesheets/custom.scss
 .
.
.
/* forms */
.
.
.
#error_explanation {
  color: red;
  ul {
    color: red;
    margin: 0 0 30px 0;
  }
}

.field_with_errors {
  @extend .has-error;
  .form-control {
    color: $state-danger-text;
  }
}
```
失敗時のテスト

```ruby:
$ rails generate integration_test users_signup
```

```ruby:test/integration/users_signup_test.rb
 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
```

ユーザー登録成功

```ruby:app/controllers/users_controller.rb

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

※redirect_to user_url(@user)と同じ意味になる
```
テンプレート内にflashのメッセージが差し込まれる

```ruby:app/views/layouts/application.html.erb
 <!DOCTYPE html>
<html>
  .
  .
  .
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <% flash.each do |message_type, message| %>
        <div class="alert alert-<%= message_type %>"><%= message %></div>
      <% end %>
      <%= yield %>
      <%= render 'layouts/footer' %>
      <%= debug(params) if Rails.env.development? %>
    </div>
    .
    .
    .
  </body>
</html>
```
ユーザ登録本番（実際にrails s で行う)

```ruby:データベースの内容を一旦リセットしてしまいましょう。

$ rails db:migrate:reset
```
成功時のテスト

```ruby:test/integration/users_signup_test.rb
 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
```

assert_differenceというメソッドは第一引数に文字列 (’User.count’) を取り、assert_differenceブロック内の処理を実行する直前と、実行した直後のUser.countの値を比較します。第二引数はオプションですが、ここには比較した結果の差異 (今回の場合は1) を渡します。


pushして7章終わり終わり。