【Rails】deviseでログイン機能を作る

# はじめに
課題で読んだ本の感想を投稿するアプリケーションを作りましたが、色々と苦戦しましたので備忘録として記事を投稿しようと思います。
今回はdeviseを使ったユーザーの新規登録・ログイン・ログアウト機能の実装について記載します。

# 環境
- 開発 (cloud9)
- 言語 (Ruby 2.6.3)
- フレームワーク(Rails 6.1.6)

# 前提
- deviseを導入している
※導入方法については[【Rails】deviceの導入](https://qiita.com/va6Gjz/items/5b3c3fc673777ebf3332)でまとめていますので、参考にしていただけたらと思います。

# モデルを作成する
ユーザー機能を作成する際はテーブルなど色々作る必要がありますが、deviceはモデルの作成すると自動的に必要なデータを作成してくれます。まずはモデルを作成しましょう。

※このコマンドはdevice独自のものになります。
```:terminal
$ rails g devise モデル名
```
今回は「User」という名前のモデルを作成します。
```:terminal
$ rails g devise User
```
これで最低限の必要なテーブルやカラムも一緒にできていると思います。
モデルを作成後、マイグレーションファイルが作成されているか確認しておきましょう。

# 初期設定を編集する
デフォルトでは、ユーザー登録・ログインの時に「メールアドレス」「パスワード」を入力するようになっているかと思います。
今回は、それを編集して下記のことができるように設定します。
- ユーザー登録の時に「名前」「メールアドレス」「パスワード」を設定するようにする
- ログイン後、ユーザーのプロフィールとして「名前」「自己紹介文」を編集できるようにする
- ログイン時に「名前」「パスワード」を入力するようにする

# 初期設定を編集する -カラムの追加
#### ユーザー登録の時に「名前」「メールアドレス」「パスワード」を設定するようにする
初期設定で「メールアドレス」「パスワード」を設定するようになっていますので、「名前」も登録できるように設定します。
先ほど作られたマイグレーションファイルに名前を保存するカラムを追加します。

※20XX0101000000はファイルが作成された年月時分秒になります。

```ruby:db/migrate/20XX0101000000_devise_create_users
class DeviseCreateUsers < ActiveRecord::Migration[6.1]
  def change
  :
  :

  ## 名前を保存するカラムを追加
  t.string :name

  t.timestamps null: false
  end
  :
  :
end
```

#### ログイン後、ユーザーのプロフィールとして「名前」「自己紹介文」を編集できるようにする
今後、ユーザーのプロフィールとして「名前」「自己紹介文」を設定できるようにしたかったので、名前を保存するカラムと一緒に、自己紹介のカラムも作りました。

```ruby:db/migrate/20XX0101000000_devise_create_users
class DeviseCreateUsers < ActiveRecord::Migration[6.1]
  def change
  :
  :

  ## 名前を保存するカラム
  t.string :name
  ## 自己紹介文を保存するカラムを追加
  t.text :introduction

  t.timestamps null: false
  end
  :
  :
end
```
必要なカラムを入力し終わったら、マイグレーションファイルをデーターベースに反映させます。以下のコマンドを実行しましょう。
```:terminal
$ rails db:migrate
```

# 初期設定を編集する -viewファイルの編集
#### viewファイルを用意する
名前の入力ができるように入力フォームを編集したいのでファイルを用意します。deviceではデフォルトでviewファイルが用意されていますので、そちらのファイルを編集できるようにしましょう。
```:terminal
$ rails g devise:views
```
これで`app/views/device`にviewファイルが作成されます。

#### 名前の入力フォームを追加する
viewファイルを編集して、名前の入力フォームを追加します。
ファイルの場所は以下になります。
`app/views/devise/registrations/new.html.erb`
```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>
  :
  :
```

# 初期設定を編集する -パラメーターの許可
初期状態では「メールアドレス」と「パスワード」の情報しか受け取ることができない状態です。そのため、追加した情報も受け取れるようにする必要があります。同時に「名前」と「パスワード」でログインできるよう設定していきます。

#### ログイン時に「名前」と「パスワード」を入力する設定へ変更する
以下のファイルを編集します。
`config/initializers/devise.rb`

このファイルの中から以下のコードを変更します。

```ruby:config/initializers/devise.rb
# 変更前
# config.authentication_keys = [:email]
```
```ruby:config/initializers/devise.rb
# 変更後
config.authentication_keys = [:name]
```
上記はログイン時に使用する値の設定についてのコードになります。
初期設定では`[:email]`、つまりメールアドレスでログインするような設定になっています。ですので名前でログインできるように`[:name]`へ変更します。

#### コントローラーを編集する
コントローラーを編集して、指定したデータを保存する許可を与えます。
以下のファイルにコードを追加しましょう。
`app/controllers/application_controller.rb`
```ruby:app/controllers/application_controller.rb
class DeviseCreateUsers < ActiveRecord::Migration[6.1]
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  # configure_permitted_parametersメソッドの定義
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:email])
  end
end
```

`before_action :configure_permitted_parameters, if: :devise_controller?`は「deviceの機能(ユーザー登録やログインなど)が使う時に`configure_permitted_parameters`メソッドを実行してください」というコードです。
`devise_parameter_sanitizer.permit(:sign_up, keys: [:email])`はdeviceを使う時のストロングパラメーターを追加する役割のコードらしいです。先ほど、`devise.rb`で設定したストロングパラメーターはnameとpasswaordになりますので、コントローラーでemailを追加する必要があります。


# 初期設定を編集する -viewファイルの編集
現在、メールアドレスとパスワードでログインする画面の設定になっていますので変更します。
メールアドレスのフォームのコードを削除して、名前のフォームのコードを追加しましょう。
ファイルの場所は以下になります。
`app/views/devise/sessions/new.html.erb`
```erb:app/views/devise/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 :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>
  <!-- ここまで削除 -->

  <div class="field">
    <%= f.label :password %><br />
    <%= f.password_field :password, autocomplete: "current-password" %>
  </div>
  :
  :
```

# ログアウトできるようにする
ログアウトの機能はdeviceが作成してくれているので、リンクを用意するだけでログアウトできるようになります。
今回はヘッダーから新規登録・ログイン・ログアウトができるような設定にします。

ファイルの場所は以下になります。
`app/views/layouts/application.html.erb`

```erb:app/views/layouts/application.html.erb
  :
  :
  <body>
    <header>
      <!-- ここから -->
      <% if user_signed_in? %>
        <li>
          <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
        </li>
      <% else %>
        <li>
          <%= link_to "新規登録", new_user_registration_path %>
        </li>
        <li>
          <%= link_to "ログイン", new_user_session_path %>
        </li>
      <% end %>
      <!-- ここからまで追加 -->
    </header>

    <%= yield %>
  </body>
  :
  :
```
`<% if user_signed_in? %>`はdeviceのヘルパーメソッドです。もしログインしているなら`<%= link_to "ログアウト"〜`の部分が処理され、ログインしていないのなら`<% else %>`以降が処理されます。

これでdeviseを使ったユーザーの新規登録・ログイン・ログアウト機能の実装完了です。

# 補足
初期設定では、新規登録・ログイン後やログアウト後はルートページに移動する設定になっているかと思います。こちらの変更方法を補足として記載します。
今回は新規登録・ログイン後、ログアウト後にaboutページへ移動する設定にしました。編集するのは、先ほど使用したコントローラーです。

ファイルの場所は以下になります。
`app/controllers/application_controller.rb`
```ruby:app/controllers/application_controller.rb
class DeviseCreateUsers < ActiveRecord::Migration[6.1]
  before_action :configure_permitted_parameters, if: :devise_controller?

  # 新規登録・ログイン後のページ移動先を設定
  def after_sign_in_path_for(resource)
    about_path #移動させたいページのルートを記載
  end

  # ログアウト後のページ移動先を設定
  def after_sign_out_path_for(resource)
    about_path #移動させたいページのルートを記載
  end

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:email])
  end
end
```
初期設定では`root_path`に設定されています。その設定を変更することで、どのページへ移動させるかの再設定ができます。

# 最後に
記事をご覧いただきありがとうございました。
記事の内容に誤りや理解不足な点がありましたら、ご指摘いただけると幸いです。