【Rails】devise nameカラムを追加して名前でログインする方法

## はじめに
deviseを使い始めたときにハマった部分があったので，記事に残しておきます。

※この記事は，deviseが導入済みであることが前提です。
導入方法については，前回の記事[【Rails】deviseの導入方法]　(url)にまとめていますので参考にしてみてください。

【**環境**】

- macOS Catalina 10.15.7
- Vagrant 2.2.4 (CentOS 7.1)
- Ruby 2.5.7
- Rails 5.2.4.4
- devise 4.7.3

## 手順
全体の流れは以下のようになっています。

**1. nameカラムを追加する
2. devise.rbの設定を変更する
3. コントローラーを編集する
4. Viewを編集する**
___
   
### 1. nameカラムを追加する

マイグレーションファイルを新しく作成します。Userモデルにnameカラムを追加する場合は下記のようにコマンドを実行します。

```:ターミナル

$ rails g migration add_name_to_users name:string
```

以下のような画面が表示されたらOKです。

```:ターミナル

    invoke  active_record
    create    db/migrate/20201104152112_add_name_to_users.rb
```

マイグレーションファイルを確認すると以下のように記述されています。

```Ruby:db/migrate/YYYYMMDDHHMMSS_add_name_to_users.rb

class AddNameToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :name, :string
  end
end
```


DBに反映するため，マイグレーションを実行します。

```:ターミナル

$ rails db:migrate
```
以下のように表示されればOKです。

```:ターミナル

== 20201104152112 AddNameToUsers: migrating ==================================
-- add_column(:users, :name, :string)
   -> 0.0042s
== 20201104152112 AddNameToUsers: migrated (0.0043s) =========================
```

これでUserモデルにnameカラムが追加され，DBに反映されました。

___

### 2. devise.rbの設定を変更する
emailの代わりにnameでログインするためには，devise.rbの設定を変更する必要があります。（私が以前ハマったのはこの変更をしていなかったためでした。忘れずに行いましょう！）

app/config/initializers/devise.rb の
**config.authentication_keys = [:email]** のコメントアウトを外し
**config.authentication_keys = [:name]** に変更します。

```:app/config/initializers/devise.rb 
# 該当箇所は⌘Fで検索すると早いです。

  # ==> Configuration for any authentication mechanism
  # Configure which keys are used when authenticating a user. The default is
  # just :email. You can configure it to use [:username, :subdomain], so for
  # authenticating a user, both parameters are required. Remember that those
  # parameters are used only when authenticating and not when retrieving from
  # session. If you need permissions, you should implement that in a before filter.
  # You can also supply a hash where the value is a boolean determining whether
  # or not authentication should be aborted when the value is not present.

  # config.authentication_keys = [:email] この行を下のように変更する
    config.authentication_keys = [:name]
```

これで，emailの代わりにnameで認証するように設定を変更できました。

___

### 3. コントローラーを編集する
次にapplication_controller.rbを編集します。

```Ruby:controllers/application_controller.rb

class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end
```

**before_action :configure_permitted_parameters, if: :devise_controller?**
これについて簡単に説明すると，deviseを使用する際にはまず最初に configure_permitted_parameters メソッドを実行することを示しています。メソッドはその下に定義しています。

**devise_parameter_sanitizer.permit(:sign_up, keys: [:name])**
これは，サインアップする際にnameの値を送信することを許可することを示しています。emailやpasswordの値はデフォルトで許可されています。

つまり，deviseの処理が実行される際に，configure_permitted_parameters メソッドによって，nameの値を使えるようにしているんだな，と思っていただければ大丈夫です。

（protectedってなんぞや？と思われた方は「rails ストロングパラメータ」などで検索してみると幸せになれると思います。）
___

### 4. Viewを編集する
devise関連のviewは以下のコマンドで作成できます。

```:ターミナル

$ rails g devise:views
```

```:ターミナル

      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/devise/shared
      create    app/views/devise/shared/_error_messages.html.erb
      create    app/views/devise/shared/_links.html.erb
      invoke  form_for
      create    app/views/devise/confirmations
      create    app/views/devise/confirmations/new.html.erb
      create    app/views/devise/passwords
      create    app/views/devise/passwords/edit.html.erb
      create    app/views/devise/passwords/new.html.erb
      create    app/views/devise/registrations
      create    app/views/devise/registrations/edit.html.erb
      create    app/views/devise/registrations/new.html.erb
      create    app/views/devise/sessions
      create    app/views/devise/sessions/new.html.erb
      create    app/views/devise/unlocks
      create    app/views/devise/unlocks/new.html.erb
      invoke  erb
      create    app/views/devise/mailer
      create    app/views/devise/mailer/confirmation_instructions.html.erb
      create    app/views/devise/mailer/email_changed.html.erb
      create    app/views/devise/mailer/password_change.html.erb
      create    app/views/devise/mailer/reset_password_instructions.html.erb
      create    app/views/devise/mailer/unlock_instructions.html.erb
```

viewの作成が完了しました。

ここからの作業は2つです。

- **サインアップ画面を編集して，nameを登録できるようにする。**
- **ログイン画面を編集して，nameでログインできるようにする。**

順に見ていきます。

まず，サインアップ画面のviewは，app/views/devise/registrationsにある new.html.erb になりますので，これを編集します。

```:app/views/devise/registrations/new.html.erb

<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <%# 追加 %>
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
  </div>
  <%# ここまで %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

#中略
```

サーバーを立ち上げて /users/sign_up にアクセスします。
<img width="400" alt="signup_name.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700730/8b128db4-e384-857a-31c0-bd2124987bca.png">

これでサインアップ画面に名前を入力する欄ができました。


次にログイン画面のviewは，app/views/users/sessionsにある new.html.erb になりますので，これを編集してnameでログインできるようにしていきましょう。

```:app/views/users/sessions/new.html.erb

<h2>Log in</h2>

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
  <div class="field">

    <%# 削除 %>
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
    <%# ここまで %>

    <%# 追加 %>
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
    <%# ここまで %>

  </div>

#中略
```
/users/sign_in にアクセスしてみます。
<img width="400" alt="login_name.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700730/5fbbef0f-5807-cdd0-abb9-9a00e370a989.png">

以上で，名前でのログインが可能になりました。

## 参考文献
この記事は，以下の情報を参考に執筆しました。

[devise機能を使ったユーザーログインガイド&名前でログイン](https://hajimeteblog.com/devise/)
[deviseでnameとpasswordのみでユーザー登録とログインできるように、初心者がdeviseをカスタマイズ！〜徹底的にゆっくり解説〜](https://qiita.com/hirokihello/items/a1ddf68d35f3cb7f2779)
[before_actionとストロングパラメーターの編集について](https://qiita.com/okamoto_ryo/items/52e3506e06c27631395e)