【Rails】ユーザー登録フォームの作成その1【Rails Tutorial 7章まとめ】

##newアクションとルーティング
ユーザーを新規登録するため、newアクションで新しいUserオブジェクトを作成し、@user変数に入れておく。

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

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

  def new
    @user = User.new
  end
end
```
ルーティングはURLを/signupとして、usersコントローラのnewアクションに紐づけておく。

```config/routes.rb
Rails.application.routes.draw do
  .
  .
  .
  get  '/signup', to: 'users#new'
  resources :users
end
```

##ユーザー登録フォーム
form_forヘルパーメソッドを使って、ユーザーの新規登録フォームを作る。
form_forはUserオブジェクトを引数にとり、その属性でフォームを生成する。

ユーザー登録フォームは次のようになる。
app/views/users/new.html.erb

```app/views/users/new.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は次のようになる。

```app/views/users/new.html
<form accept-charset="UTF-8" action="/users" class="new_user"
      id="new_user" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <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>
```

##form_forを使ったフォームの構造
###form_forの役割
form_forは変数fを使ったブロックをとる構造になっており、次のようなhtmlを生成する。

```.html
<%= form_for(@user) do |f| %>
  .
  .
  .
<% end %>
↓
<form accept-charset="UTF-8" action="/users" class="new_user"
      id="new_user" method="post">
  .
  .
  .
</form>
```
action属性は"/users"、method属性は"post"となっている。
この2つの属性は、/usersに対してHTTPのPOSTリクエストを送信する、といった指示をしている。
すると、Usersリソースが提供するRESTfulなルート（https://qiita.com/kagamiya9/items/48f66b20aee03fe9da1f ）に基づいて、createアクションに行き着く。

このような流れが自動でできるのは、次のような理由らしい。
①form_forの引数は@userであり、Railsは＠userがUserクラスであることを認識する。
②@userはnewアクションで新規作成されているため、Railsはpostメソッドを使ってフォームを構築すべきだと判断する。


###各入力フォーム
nameの入力フォームは次のようになる。

```.html
<%= f.label :name %>
<%= f.text_field :name %>
↓
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />
```

emailの入力フォームは次のようになる。

```.html
<%= f.label :email %>
<%= f.email_field :email %>
↓
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" type="email" />
```
nameのtype属性は"text"だが、emailでは"email"である。
前者はf.text_field、後者はf.email_fieldとすることでtype属性がそれぞれ決まっている。
こうすると、スマホなどではメールアドレス入力用のキーボードが表示されるようになっている。

passwordの入力フォームは次のようになる。

```.html
<%= f.label :password %>
<%= f.password_field :password %>
↓
<label for="user_password">Password</label>
<input id="user_password" name="user[password]" type="password" />
```
type属性がpasswordの場合、フォームに文字を入力すると黒丸•で表示されるようになる。

password_confiramtionの入力フォームは次のようになる。

```.html
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
↓
<label for="user_password_confirmation">Confirmation</label>
<input id="user_password_confirmation"
         name="user[password_confirmation]" type="password" />
```
password_confirmationでは、f.labelの第二引数に文字列"Confirmation"をとっている。
これにより、フォーム上のラベルが指定した文字列になる。
他のフォームは属性ごとに自動で設定されている。
(nameはNameになる。なお、"Confirmation"を除くと、Password confirmationになる)
サブミットボタンも同様で、value属性が任意の文字列になる。

##Createアクションの作成
###name属性によるハッシュの構成

```.html
<input id="user_name" name="user[name]" - - - />
<input id="user_password" name="user[password]" - - - />
```
inputには特殊なname属性がついている。
Railsはnameの値を使って、初期化したハッシュを (params変数経由で) 構成する。

どういうことかというと、送信された内容はまず次のようなハッシュになり、params変数に代入される。

```.rb
params = { users: { name: "Foo Bar", email: "foo@invalid", 
           password: "foo", password_confirmation: "bar" } }
```

createアクションでは、このparams変数を使ってユーザーを新規登録する。

```.rb
@user = User.new(params[:user])
```
:userシンボルの値は、入力される属性(nameやemail)とその値からなるハッシュなので、上のコードは次のコードと同じである。

```.rb
@user = User.new(name: "Foo Bar", email: "foo@invalid",
                 password: "foo", password_confirmation: "bar")
```

###Strong Parameters
上のようなコードはセキュリティ上問題があるらしい。
paramsをそのまま送信すると、管理者用の属性であるadminなどの値を送信して、管理者権限を奪われるからだとか。
この辺は説明が非常に分かりにくいのだが、要は許可された属性以外は送信できないようにする、ということだ。

結局のところ、次のようなuser_paramsメソッドをコントローラ内に作る。
これはStrong Parametersと呼ばれる。
先の問題があるコードは、マスアサイメントと呼ばれる。

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

private内にあるメソッドはweb経由で外部に晒されることがない。

###ユーザー登録に失敗した場合の処理
ユーザー登録に失敗した場合は、renderメソッドを使って新規登録ページに戻り、エラーメッセージを表示する。
エラー部分は長いので別記事にまとめることにする。

###ユーザー登録に成功した場合の処理
成功部分も別記事にまとめることにする。