コーディング未経験のPO/PdMのためのRails on Dockerハンズオン vol.8 - Sign up -

# はじめに
第８回目です。前回、Userモデルを作り上げユーザー詳細ページを作成するところまでいきました。
今回は、ユーザーをUIから登録すべくSign upページを作っていきたいと思います。

いままではRailsコンソールからモデルを操作してユーザーを作成していましたが、今回からはMVCを連携させてユーザーを作成させるようにします。

# 前回のソースコード
前回のソースコードはこちらに格納してます。今回のハンズオンからやりたい場合はこちらからダウンロードしてください。

- [at946/rails_on_docker_handson at vol.07](https://github.com/at946/rails_on_docker_handson/tree/vol.07)

# Sign upページの作成
今回はSign upページでユーザーの`name`、`email`、`password`を入力してもらい、登録完了後そのユーザーのユーザー詳細ページに遷移させます。
まずは、このアプリを実現するために必要なファイルや設定を作成していきます。

今回、Sign upページにアクセスするためのRouting、Action、Viewと、実際にUserをDBに登録するRouting、Actionが必要になります。

Scaffoldを思い出してみてください。
あの時、新規にユーザーを作成するには`/users/new`のページにアクセスしており、`new`アクションがありました。
そこで登録ボタンを押すと、`/users`のURLにPOSTメソッドでリクエストが飛び`create`アクションがDBにユーザーを保存していました。

では、これらの設定を元にRouting、Action、Viewをコーディングしていきましょう！

## Routing
まず、`users#new`、`users#create`へのルーティングを作成します。
しかし、Sign upページと呼んでいるのですから`/users/new`のようなURLでは少しカッコつきません。
今回は`/sign_up`にGETリクエストしたときに`users#new`にルーティングされるように定義していきましょう。
`users#create`へのルーティングも`/sign_up`にPOSTリクエストしたときに定義します。

```diff:config/routes.rb
  Rails.application.routes.draw do
    root 'static_pages#home'
+
+   get   '/sign_up',  to: 'users#new',    as: :sign_up
+   post  '/sign_up',  to: 'users#create', as: :create_user
    resources :users, only: [:show]
  end
```
基本となるルーティング定義の書き方は以下の通りです。

```rb
[method] '[path]', to: '[controller_name]#[action_name]', as: '[route_name]'
```
このコーディングで
「`path`に`method`でリクエストされた場合、`controller_name`コントローラーの`action_name`アクションにルーティングする。アプリのコードとして`route_name`_pathと表現された場合は、このルーティングを表すことと定義する。」
ということをRailsアプリケーションに定義立てています。

`route_name`はシンボル（`:sign_up`のように`:`を頭につけてる文字）で書いてます。シンボルは複数あっては困るものなどに使用するそうです（参考: 「[Rubyのシンボルと文字列の違い | UX MILK](https://uxmilk.jp/25934)）。
ルートの名前も重複しては困りますので、シンボルを使っています。

ルーティングの設定はこれで完了です。次はコントローラーに新しくアクションを用意しましょう。

## Action
次にUserコントローラーに`new`アクションを追加します。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController
    def show
      @user = User.find(params[:id])
    end
+
+   def new
+     @user = User.new
+   end
+
+   def create
+   end
end
```
`new`アクションでは、インスタンス変数`@user`に`User.new`を代入しています。
これはView側でUserモデルを扱ってフォームを作っていくために空のモデルが必要なのです。
詳しくはView側で説明しますので、ひとまずそのままコピペでお願いします。

`create`アクションはとりあえず定義だけしておきます。処理はのちのち。

## View
ではでは、Viewファイルを作っていきます。
`new`アクションでrenderされるViewなので`new.html.erb`ファイルを作成します。

```
$ docker-compose up -d
$ docker-compose exec web ash
```

```
# touch app/views/users/new.html.erb
```

```erb:app/views/users/new.html.erb
<div class="container">
  <h1 class="my-5">Sign up</h1>

  <%= form_with model: @user, url: create_user_path, local: true do |form| %>
    <div class="form-group">
      <%= form.label :name %>
      <%= form.text_field :name, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= form.label :email %>
      <%= form.text_field :email, class: "form-control" %>
    </div>
    <div class="form-group">
      <%= form.label :password %>
      <%= form.password_field :password, class: "form-control" %>
    </div>

    <div class="form-group mt-5">
      <%= form.submit "Sign up!", class: "form-control btn btn-primary" %>
    </div>
  <% end %>
</div>
```
構文自体はそこまで難しくないですね。`http://localhost:3000/sign_up`にアクセスしてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/bccb642f-f076-ba35-51d7-5409bc0242e3.png)
なかなかぽいページになったんじゃないでしょうか？
`password_confirmation`は使わないことにしました。「[登録フォームにおけるパスワード確認用の入力欄は必要か | UX MILK](https://uxmilk.jp/18568)」の記事を参考にしまして。
いくつかrubyコードが埋め込まれているので説明していきますね。

### form_with
こういうのをビューヘルパー（View helper）っていいます。
『[form_with](https://api.rubyonrails.org/v6.0.2/classes/ActionView/Helpers/FormHelper.html#method-i-form_with)』ヘルパーは`form`タグを生成してくれるヘルパーです。
`model`をオプションに指定することでそのモデルオブジェクトのためのフォームを作ってくれるようになります。上のコードのようにブロック形式で`form`変数を使うことで、例えば`form.input_field :name`とするだけで`@user`の`name`属性に関するinputフィールドを作ってくれるようになるので、これは超便利です。

`url`オプションはフォームの送信先を定義します。`create_user_path`は`routes.rb`で`users#create`へのルーティングにつけた名前ですね。
このようにコーディングすることで`create`アクションにフォームを送信できるようになります。

また、`local: true`オプションも付けています。`form_with`ヘルパーではデフォルトでAjax通信でフォームをポストします。つまり、画面遷移なしでフォームをリクエストするんです。これはこれで便利な場面もあって今時な感じなんですが、今回はユーザーの新規作成が成功したらそのユーザーのマイページに画面遷移させたいので、`local: true`オプションでAjax通信をオフにしています。
ちなみに『Ajax』は『エイジャックス』または『アジャックス』と読むそうです。僕は『エイジャックス』って読んでます。

今回の`form_with`は実際にクライアントに返却される場合は以下のように変換されて返却されています。

```erb
<%= form_with model: @user, url: create_user_path, local: true do |form| %>
  ...
<% end %>
```
↓

```html
<form action="/sign_up" accept-charset="UTF-8" method="post">
  <input type="hidden" name="authenticity_token" value="xxxxxxxxxx">
  ...
</form>
```
`authenticity_token`が第３回の時に少し触れた、CSRFトークンですね。XSSを防いでくれるやつです。

### label
`label`はラベルを付けてくれるやつです。ページで『お名前』とか『メールアドレス』と出ているやつのことです。

```erb
<%= form.label :name %>
```
↓

```html
<label for="user_name">お名前</label>
```

### text_field
`text_field`は`input type="text"`タグでテキストフィールドを作り出してくれます。
使い方も簡単で、`text_field [attribute_name], [options]`なだけです。
今回はBootstrapの`form-control` classをオプションで付けてあげています。

```erb
<%= form.text_field :name, class: "form-control" %>
```
↓

```html
<input class="form-control" type="text" name="user[name]" id="user_name">
```
`name`や`id`も勝手に付けてくれているのがいいですよね。
ここで`id="user_name"`を付与してくれているので、`label`の`for="user_name"`と紐付けができるようになっています。

### password_field
`password`を入力するフォームのところでは`password_field`を使いました。
これは`text_field`と似ていますが、`input type="password"`タグのフィールドを作ってくれるやつです。

```erb
<%= form.password_field :password, class: "form-control" %>
```
↓

```html
<input class="form-control" type="password" name="user[password]" id="user_password">
```
`input type="password"`はパスワード用の入力フィールドを作り出せるので、入力した文字が『●』でマスク化されるようになります。

### submit
`submit`タグはフォーム送信用のボタンを作ってくれるタグです。`input type="submit"`を作ってくれるんですね。

```erb
<%= form.submit "Sign up!", class: "form-control btn btn-primary" %>
```
↓

```html
<input type="submit" name="commit" value="Sign up!" class="form-control btn btn-primary" data-disable-with="Sign up!">
```
HTMLの方にある`data-disable-with`はダブルクリック抑止のためのパラメータですね。RailsのERBを使えばこういった必要だけどついつい忘れてしまいがちなHTMLオプションも自動で付与してくれるので積極的に利用するといいと思います。

これ以外にもいろいろなヘルパーが用意されているので、HTMLのあのタグはどうやって書けばいいのか、と思った時は直接HTMLタグを書くのではなく一度Railsでの書き方をググってみるといいでしょう！


これでViewがいい感じに作れました。次は「Sign up!」ボタンを押した時の処理をコーディングしていきます。

## Createアクションをコーディング
ここまでで`new.html.erb`のフォームから`create`アクションにフォームをリクエストできるようになりました。
ここからは`create`アクションでリクエストされたフォームのデータからDBにUserを登録できるようにします。

では、先ほど"とりあえず"作った`create`アクションをコーディングしていきます。

```diff:app/controllers/users_controller.rb
  class UsersController < ApplicationController
    def show
      @user = User.find(params[:id])
    end

    def new
      @user = User.new
    end

    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)
+     end
  end
```
はい。初見だとけっこう複雑に見えるんじゃないかなーと思います。
１行ずつみていきましょう。

```
@user = User.new(user_params)
```
まず、`@user`に`User.new(user_params)`を代入しています。
`user_params`とは何でしょう？

```
private
  def user_params
    params.require(:user).permit(:name, :email, :password)
  end
```
`user_params`はここで定義されている関数ですね。
`params.require(:user).permit(:name, :email, :password)`の部分は『<b>ストロングパラメーター（Strong parameter）</b>』と呼ばれています。Railsが用意しているこのストロングパラメーターは意図しないデータのPOSTを防いでくれます。

```rb
params.require([model_name]).permit([attribute_names])
```
これでリクエスト内のパラメーター（`params`）から`model_name`モデルに紐づくデータのみを抽出し、さらにその中から`attribute_names`に指定されているデータのみを抽出して返却します。
それ以外のデータはドロップします。これによってユーザーのいたずらで意図しないデータが作られてしまうことを防ぐということです。
例えばモデルにはこっそり`admin`フラグみたいなものがあって`1`のユーザーはなんでもできちゃう権限を持っているとします。いたずらっ子のユーザーがそれに気づいてSign upページにdeveloper toolsとかを使って`admin=1`のフォームを追加してきたりしたとします。ここでストロングパラメーターを使っていない場合は`admin=1`でユーザーが作成されてしまいアプリが乗っ取られてしまう、みたいなことが起きちゃうんですね。
ストロングパラメーターはそういった意図しないフォームからのリクエストを無視するようになるので、安全なアプリケーションの作成に不可欠なものなのです。

今回は`User`モデルの`name`、`email`、`password`以外のデータは無視することを定義しています。

また、この関数は`private`より下に書かれています。これはクラス内からのみアクセスできる関数であることを定義しています。

さて、ここまでで`@user`に`user_params`で抽出されたデータが初期値として設定された`User`モデルオブジェクトが代入される、ということになります。

```rb
if @user.save
  redirect_to @user
else
  render :new
end
```
次は、この`@user`を`save`して条件分岐しています。ModelのCRUDの時にも話がでてきましたが`save`メソッドはバリデーションを通りデータをDBに保存できた場合`true`を、バリデーションに引っかかった場合`false`を返却します。
その結果を元に`true`の場合は`redirect_to @user`、`false`の場合は`render :new`が実行されます。

```rb
redirect_to @user
```
`redirect_to`メソッドは引数に`GET`メソッドでリダイレクトします。
引数には`@user`を指定してます。これは、`user_path(@user)`と同義です。`user_path`は`show`メソッドにつけられている名前です。`@user`には今DB保存が成功したUserモデルオブジェクトが入っていますので、今保存したユーザーのユーザー詳細ページに遷移させています。

```rb
render :new
```
`false`の場合はこちらが実行されます。
`render`メソッドは指定したアクションのViewファイルをレンダリングするメソッドです。（いろいろと使い方はありますが、今回はこんな説明で）
通常アクションは自分の名前と同じViewファイルをレンダリングするようになっていますが、`render`メソッドを使うことで別のアクションのViewファイルをレンダリングするようにすることもできます。
この場合は、`new`アクションのViewファイルがレンダリングされます。さらに`@user`には今`false`になったUserモデルオブジェクトが入った状態で`new.html.erb`に引き渡されます。
そのため、レンダリングされたとしても今入力してた属性データは再表示されるはずだし、`@user.errors`の中には`save`に失敗した理由も残っているわけです。`new.html.erb`側を少し更新すればエラーメッセージを表示することもできます。

## `new.html.erb`でエラーメッセージを表示できるように更新
ということで`new.html.erb`を更新して、`save`でエラーが発生した場合は`errors.full_messages`が表示されるようにしてみましょう。

```diff:app/views/users/new.html.erb
  <div class="container">
    <h1 class="my-5">Sign up</h1>
+
+   <% if @user.errors.any? %>
+     <div class="alert alert-danger">
+       <ul class="mb-0">
+         <% @user.errors.full_messages.each do |msg| %>
+           <li><%= msg %></li>
+         <% end %>
+       </ul>
+     </div>
+   <% end %>

    <%= form_with model: @user, url: create_user_path, local: true do |form| %>
    ...
  </div>
```
これも少し説明します。

```erb
<% if @user.errors.any? %>
  ...
<% end %>
```
まず一番外側を囲っている部分です。
`any?`メソッドは対象が"空"でないかどうかを検証して「空でない」場合に`true`を返します。
今回は`@user.errors`に対して`any?`メソッドを適用しているので、validationによるエラーがある場合に`true`になります。

```erb
<div class="alert alert-danger">
  <ul class="mb-0">
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
  </ul>
</div>
```
`@user.errors.any?`が`true`の場合にはこの部分が表示されることになります。
`ul`タグはリストを表示するためのタグですね。`li`タグが`ul`タグのアイテムとして『・』を頭につけた箇条書き形式で表示されるようになっています。
`li`タグは以下のコードに囲まれています。

```erb
<% @user.errors.full_messages.each do |msg| %>
  <li><%= msg %></li>
<% end %>
```
`@user.errors.full_messages`はバリデーションの回でも使ったので覚えている人が多いと思います。
バリデーションでエラーが起きた時にユーザーにそのまま見せれるようなエラーメッセージが配列で格納されていたやつです。
それを`each`でひとつずつ取り出し、`msg`に格納して、`@user.errors.full_messages`がなくなるまでブロックの中の処理を繰り返します。
ブロックの中の処理は`<li><%= msg %></li>`だけなので、ここで`@user.errors.full_messages`のエラーメッセージを一つずつ`li`タグで囲って表示してあげていますね。
結果として、全てのエラーメッセージが箇条書きの形式で表示されるようになると期待できます。

ここまでできたら実際に動作確認をしてみましょう！

# 動作確認（エラー編）
まずはエラーの場合の動作確認をしてみます。
以前Userモデルのバリデーションを確認したときのように、いくつかのエラーケースでエラーメッセージが表示されるかどうかを確認していきましょう。

## 存在性チェック
Userモデルでは`name`、`email`、`password`全てが入力必須（`presence`）な項目です。
何も入力していなければエラーになるはず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/57e20327-f8f2-aac3-5f05-a0efc1ed8f69.png)
実際に何も入力せずに「Sign up!」ボタンを選択したページがこちらです。
「お名前」「メールアドレス」「パスワード」について、それぞれエラーが出ていてUserの作成がうまくいかなかったことがわかりますね。

## 文字数チェック
`name`と`email`にはそれぞれ最大50文字、255文字の制限を設けていました。
それ以上の文字数でエラーになるか確認してみましょう。

51文字と256文字の文字列は↓をお使いください。

```
Name
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Email
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb@sample.com
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/5813d402-3d48-1008-814b-02ff839f2ebe.png)
文字数制限のエラーが出ていますね。
ちなみに「パスワード」には適当にパスワードを入力して「Sign up!」ボタンを選択したので「パスワード」に関するエラーは出ていないです。「パスワード」は`type="password"`のフィールドを使っているので、エラー時に元の値が反映されないようになっているんですね。

## フォーマットチェック
`email`にはフォーマットの検証もいれていました。例えば「＠」がない場合はメールアドレスとしておかしいのでちゃんとエラーが返却されるか確認してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/84272694-4aef-2aae-59b3-69a199bf581c.png)
ちゃんとエラーになっていますね。

## 重複チェック
最後に`email`の重複チェックもみてみましょう。

とりあえず`john@sample.com`の`email`をもつユーザーをRailsコンソールから作っておきます。

```
# rails c
```
```pry
> User.create(name: "John Smith", email: "john@sample.com", password: "password")
   (0.3ms)  BEGIN
  User Exists? (7.3ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2  [["email", "john@sample.com"], ["LIMIT", 1]]
  User Create (17.4ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["name", "John Smith"], ["email", "john@sample.com"], ["created_at", "2020-03-09 19:22:14.408777"], ["updated_at", "2020-03-09 19:22:14.408777"], ["password_digest", "$2a$12$kGv3a06MmAJ.XapqOHTBDeAiRoPUNBse7R79n5f8WA/envU00qkq."]]
   (3.8ms)  COMMIT
=> #<User:0x0000558d40945160
 id: 1,
 name: "John Smith",
 email: "john@sample.com",
 created_at: Mon, 09 Mar 2020 19:22:14 JST +09:00,
 updated_at: Mon, 09 Mar 2020 19:22:14 JST +09:00,
 password_digest: [FILTERED]>
```
ユーザーを作ったので、同じメールアドレスを大文字とかにしてもエラーになるかを確認してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/b7866716-dae1-072d-0283-8a2bf8d61e7f.png)
これもエラーになりましたね！

ここまでチェックすれば、バリデーションはちゃんと効いていて、バリデーションエラーが起きた時のエラーハンドリングも正常に動作していることが確認できましたね。

# 動作確認（正常編）
ではいよいよユーザーを実際にUIから作ってみましょう。

今回は以下のユーザーを作ってみます。

```
name: Taro Tanaka
email: taro@sample.com
password: taro1234
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/ddc8dd62-72ef-5607-53b6-e881addea4c6.png)
ユーザー詳細ページに遷移しましたね！さらに今入力したユーザー情報もちゃんと表示されています！

# Welcomeメッセージを表示する
ユーザーが作成されて、ユーザー詳細ページにも遷移できたのですが何か物足りないですね。
そうだ、Welcomeメッセージがないんだ。

ユーザー詳細ページは、Welcomeページというわけではないので今のまま装飾していけばいいのですが、会員登録した時に限ってでも「ようこそ！」みたいなメッセージがほしいですよね。

こういう一時的にページにメッセージを表示したいときに使えるRailsの機能として`flash`があります。
`flash`はControllerで設定してあげます。今回は`create`アクションで`save`に成功した時に表示されるようにしてみましょう。
`create`アクションを通って`show.html.erb`が表示された場合はWelcomeメッセージが表示されますが、通常`show.html.erb`が表示される場合は`create`アクションは通らず`show`アクションだけを通るので、例えばリロードすればメッセージが消えるという寸法です。

```diff:app/controllers/users_controller.rb
  ...
  def create
    @user = User.new(user_params)
    if @user.save
+     flash[:success] = "サインアップありがとう！"
      redirect_to user_path(@user)
    else
      render :new
    end
  end
  ...
```
Controller側の設定はこんな感じです。`flash`に`[:success]`のような形でメッセージの`key`を定義して`= 文字列`の形で`value`を与えます。

View側でこれを受け取って、`flash`がある場合だけ表示するように、`show.html.erb`も更新しましょう。

```diff:app/views/users/show.html.erb
  <div class="container my-5">
+   <% flash.each do |msg_type, msg| %>
+     <div class="alert alert-<%= msg_type %>"><%= msg %></div>
+   <% end %>

    <%= @user.name %>
    <br>
    <%= @user.email %>
  </div>
```
今回は`flash[:success] = "サインアップありがとう！"`と定義しているので、`msg_type`に`success`が、`msg`に`サインアップありがとう！`が格納されます。
`alert-<%= msg_type %>`は`alert-success`となるわけですね。Bootstrapで`alert-success`のCSSが用意されているのでそれを適用するために`flash`のkeyを`success`にしていたわけです。
おんなじようにエラー系のメッセージにしたい場合は`danger`にしてあげたりするとViewファイルをいじらなくてもエラーっぽいCSSを適用することができます。

では実際に試してみましょう。

次は花子さんを作ってみます。`http://localhost:3000/sign_up`にアクセスして以下のデータで登録してみましょう。

```
Name: Hanako Yamada
Email: hanako@sample.com
Password: hanako1234
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/0d7a4277-8a6e-90f7-3c2e-386e53160ad4.png)
Welcomeメッセージが表示されました！

この状態でリロードしてみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/d8bc3f94-4cdd-f8e3-ea0c-486a4d48a7dd.png)
メッセージが消えましたね。期待通りの動作です。

# パスワードの表示非表示を制御する
あとそうだ。先ほどUX的に`password_confirmation`は使いませんという話をしました。
しかし、今のままではパスワードが非表示しか対応していないので、ユーザーは自分の思ったパスワードが正しく入力できているか確認できません。
ただ、周りから見えないようにするのが目的でマスク化しているので、常に平文にすることもUX的によろしくないでしょう。

ということで、「パスワードを表示する」チェックボックスを用意して、チェックが入っている間だけ表示されるようにしようと思います。
まず、`new.html.erb`にチェックボックスを追加します。
今回は`@user`に紐づかないフォーム要素になるので`check_box_tag`を利用します。これは`input type="check_box"`タグを作ってくれるやつです。

```diff:app/views/users/new.html.erb
  ...
  <div class="form-group">
    <%= form.label :password %>
    <%= form.password_field :password, class: "form-control" %>
  </div>
+ <div class="form-check">
+   <%= check_box_tag :visible_password, :visible, false, class: "form-check-input" %>
+   <%= label_tag :visible_password, "パスワードを表示する" %>
+ </div>

  <div class="form-group mt-5">
    <%= form.submit "Sign up!", class: "form-control btn btn-primary" %>
  </div>
  ...
```
↓

```HTML
...
<div class="form-group">
  <label for="user_password">パスワード</label>
  <input class="form-control" type="password" name="user[password]" id="user_password" />
</div>
<div class="form-check">
  <input type="checkbox" name="visible_password" id="visible_password" value="visible" class="form-check-input" />
  <label for="visible_password">パスワードを表示する</label>
</div>

<div class="form-group mt-5">
  <input type="submit" name="commit" value="Sign up!" class="form-control btn btn-primary" data-disable-with="Sign up!" />
</div>
...
```
はい。これでチェックボックスを追加することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/04ca9a64-144b-12b3-63fd-d827c6ca7962.png)

ただ今のままではただのチェックボックスにチェックを入れたり外したりできるだけです。
このチェックボックスの状態に合わせて「パスワード」のフィールドをマスク化したりマスク解除したりしていきましょう。
どうやるかというと、今マスク化されているのは`input`の`type`が`password`になっているからです。他の`input`のフィールドは普通に文字が見えていますが、これは`type`が`text`になっているからです。
なので、チェックボックスの状態に合わせて、チェックが入っている場合は`type="text"`、チェックが入っていない場合は`type="password"`と切り替えることができれば、パスワードの表示非表示を制御できるはずです。

これを実装するには、フロントエンドで動作するjavascript（jQuery）を使います。

ごちゃごちゃするといけないので、`application.js`ではなくファイルを追加してそちらでコーディングしていきましょう。

```pry
> quit
```
```
# touch app/javascript/packs/visible_password.js
```

```js:app/javascript/packs/visible_password.js
$(function() {
  $("#visible_password").change(function() {
    type = "password"
    if ($(this).prop("checked")) { 
      type = "text"
    }
    $("#user_password").attr("type", type)
  })
})
```
まず、型として`$(function() { ~ })`で囲みまして、`{}`の中に処理をコーディングしていきます。

```js
$("#visible_password").change(function() {
  ...
})
```
最初に`$("#visible_password").change`と書きました。これは`id`が`visible_password`の`input`タグに変化が起きたときに処理されることを意味しています。こういった何かが起こったときに処理が実行されることを『トリガー』とか『発火する』とか言うので覚えておきましょう！
今回の場合は`id`が`visible_password`の`input`の変化をトリガーにする、とか、変化が起きた時に発火する、みたいな表現をするってことです。

```js
type = "password"
```
処理の中をみると、まず最初に`type = "password"`の変数定義をしていますね。

```js
if ($(this).prop("checked")) { 
  type = "text"
}
```
その後、`if ($(this).prop("checked"))`の条件分岐を書いています。
`$(this)`はjQueryの特殊な書き方だと思いますが、トリガーの元になった要素のことです。
`prop（"checked")`はその要素のチェックボックスがチェックされているかを取得するメソッドなので、`$(this).prop("checked")`は`visible_password`のチェックボックスにチェックが入っていれば`true`、そうでなければ`false`になります。
つまり`if`文の部分は、「チェックボックスにチェックが入っていれば`type`変数を`"text"`に更新する」、ことが記述されています。

```js
$("#user_password").attr("type", type)
```
最後に、`$("#user_password")`、つまり`id`が`user_password`の要素（パスワードの`input`タグ）に`attr("type", type)`をしています。
`attr`はその要素の属性を取得したり更新したりするメソッドです。引数が２つの場合は１つ目の引数の属性を２つ目の引数の値に更新します。今回の場合は`id="user_password"`の`type`を変数`type`に更新しています。

変数`type`はデフォルトでは`password`、チェックボックスにチェックが入っている場合は`text`になるので、チェックボックスにチェックを入れるとパスワードが表示される仕組みです。

さて、実際に使えるようにするには、このファイルを読み込めるようにする必要があります。
このファイルはアプリケーションの全てのページで使うのではなく、Sign upページでのみ利用するようなファイルなので、`new.html.erb`で読み込みを定義してあげます。

```diff:app/views/users/new.html.erb
  <div class="container">
  ...
  </div>
+ <%= javascript_pack_tag 'visible_password' %>
```

Sign upページをリロードして試してみましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/5a7329c1-0f20-a58d-01d3-c787b26774b7.png)

チェックなし👆👇チェックあり

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/22c1e8a3-57a0-3674-299b-f6d2b13bd73a.png)

期待通りの動作になりましたね！

# トップページからリンクさせる
最後にトップページの「Sign up now!」ボタンからSign upページにリンクを貼ってあげましょう。

```diff:app/views/static_pages/home.html.erb
  <div class="jumbotron mb-0">
    <div class="container text-center">
      <h1>Welcome to Sample App.</h1>
      <h2>Twitterみたいなアプリです。</h2>
-     <%= link_to "Sign up now!", "#", class: "btn btn-lg btn-primary mt-5" %>
+     <%= link_to "Sign up now!", sign_up_path, class: "btn btn-lg btn-primary mt-5" %>
    </div>
  </div>
```
はい、これで完了です！`#`をサインアップページへルーティングされている名前付きルートに変えただけです。
トップページ（`http://localhost:3000/`）にアクセスして「Sign up now!」ボタンをクリックしてみましょう。ちゃんとSign upページに遷移するはずです。

# 後片付け
本日はここまでです！
いつものように、次回に向けてデータを消します。

```
# exit
```

```
$ docker-compose down
$ docker-compose run --rm web rails db:migrate:reset
```
DBコンテナが立ち上がった状態だと思うのでdownさせます。

```
$ docker-compose down
```

# まとめ
今回は、サインアップページとユーザー登録機能を作っていきました。
今までと比べると少し複雑なControllerのコーディングをしましたね。バリデーションの結果に合わせてエラーメッセージを表示させてみたり、登録完了後のウェルカムメッセージを表示させたりしてみました。

また、jQueryを使ってパスワードの表示非表示をクライアントサイドで変更するコーディングもやってみました。
jQuery（javascript）はWebアプリケーションを作る上では欠かせない技術ですのでぜひ覚えてくださいね。

さて、今回はユーザー登録はできたものの、サインイン（ログイン）してそのユーザー独自の機能を提供する、ということはできていません。例えば、今のまま開発を進めてしまっては誰もが全てのユーザーの情報をみれてしまったり更新できてしまったりします。
そこで次回は、セッション管理をすることでサインイン機能を実装してみようと思います。

では、次回も乞うご期待！ここまでお読みいただきありがとうございました！

Next: [コーディング未経験のPO/PdMのためのRails on Dockerハンズオン vol.9 - Sign in - - Qiita](https://qiita.com/at-946/items/59b46a1626f5cfbf64a4)

# 本日のソースコード
- [at946/rails_on_docker_handson at vol.08](https://github.com/at946/rails_on_docker_handson/tree/vol.08)

# Reference
- [Ruby on Rails チュートリアル：実例を使って Rails を学ぼう](https://railstutorial.jp/)
- [登録フォームにおけるパスワード確認用の入力欄は必要か | UX MILK](https://uxmilk.jp/18568)
- [Action Controller の概要 - Railsガイド](https://railsguides.jp/action_controller_overview.html#strong-parameters)
- [jQuery 属性値を取得/設定/削除する(attr/removeAttr) | ITSakura](https://itsakura.com/jquery-attr)
- [jQueryでチェックボックスのチェック状態を取得する (jQuery + JavaScript プログラミング)](https://www.ipentec.com/document/javascript-jquery-get-checkbox-value)

# Other Hands-on Links
- https://github.com/at946/rails_on_docker_handson/tree/master