【初学者向け】Devise導入(nameカラム追加)

#Devise導入
<details><summary>Deviseとは</summary>
Deviseはユーザー登録やログイン機能などの認証に必要な機能を簡単に追加できるRails用のGemです。
</details>

▼公式ドキュメント▼

https://github.com/heartcombo/devise

##Gemをインストール
まずGemfileの最下部に以下のコードを追加

```gemfile:gemfile
gem 'devise'
```

追加したgemを反映させるためにbundle installを実行。

```console:ターミナル
bundle inatall
```

次に、公式ドキュメントにあるように以下のコマンドを実行。

```console:ターミナル
rails generate devise:install
```
上記、コマンド実行で２つのファイルが生成されます。
create  config/initializers/devise.rb
create  config/locales/devise.en.yml

ファイルを作成すると、以下のようなメッセージが表示されます。

こちらはdeviseを使う上での初期設定になります。

![Qiita【devise】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/aac3ea6a-5b1f-cbb8-e354-75c2beffd950.png)

##Deviseの初期設定
###1. デフォルトURLの指定

英文の例に書いてあったconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
を以下のファイルに追加します。

メール送信の設定でメール送信の実装は行わない場合、飛ばしてOK。

```ruby:config/environments/development.rb
Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

(省略)

  # mailer setting
  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end
```

###2. root_urlの指定
「http://localhost:3000/」　
にアクセスした際に表示されるページを指定します。
現状ページは1つも作っていないため、先に追加します。

homeコントローラーと、indexページを追加してみます。

```console:ターミナル
rails g controller home index
```

関係ファイルの生成とルーティングの記述がされました。
![Qiita【devise_2】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/d95b8263-adf8-7cc5-dd07-ed5e337019e2.png)

![Qiita【devise_3】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/7e5f76d8-b64d-7c7f-4668-7cce7045e061.png)

###3. flashメッセージの設定
<details><summary>フラッシュメッセージとは</summary>
ある動作を行った時、成功したのか、もしくは失敗したのか、相手に知らせる機能のことです。
例えばメールアドレスが正しくない状態でログインしようとしたときに、ログインに失敗した旨をメッセージとして表示したりします。
</details>



```ruby:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>DeviseApp</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    ----- 追加 ----
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
    ---- ここまで追加 ----

    <%= yield %>
  </body>
</html>
```

###4. DeviseのViewを生成

Deviseの導入で追加されるViewは、以下のコマンドを実行しなければデザインを変更できないので、デザインをカスタマイズするためにも実行します。


```console:ターミナル
rails g devise:views
```

実行すると以下のようなファイルが生成されます。
コマンドを実行するだけでこれだけのファイルが生成されるのはありがたいですね！

![Qiita【devise_4】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/a11a8a26-ddd7-c517-92fb-e063709d8fd6.png)

##Userモデルを作成
以下のコマンドでDevise用のUserモデルを作成します。
(モデル名の値は任意です。作成したいモデル名で作成できます。今回はUserというモデル名で作成します。)

```console:ターミナル
rails g devise User
```

![Qiita【devise_5】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/00149d3f-b5d5-1a41-8146-aa2f572e0f31.png)

最後の行にroute devise_for :usersという記載があります。
これはconfig/routes.rbにdeviseのルーティングを追加しています。

```ruby:config/routes.rb
Rails.application.routes.draw do
  --- 自動で追加される ---
  devise_for :users
  --- ここまで ---
  get 'home/index'
end
```

##usersテーブルにnameカラムを追加
先ほどUserモデルを作成した際に、db/migrate/フォルダの中にマイグレーションファイルが作成されました。
Deviseのデフォルトではnameカラムがありません。
今回はユーザー名が必要なサービスを想定してカラム追加の記述をします。

```ruby:db/migrate/20210525153350_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      ## Database authenticatable
　　　--- 一行追加 ---
      t.string :name,               null: false
     --- ここまで追加 ----
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

　　　(以下、省略)
```

##Usersテーブル作成
マイグレーションファイルを作成しただけでは、テーブルに反映されないので、
マイグレーションファイルをテーブルに反映するにはマイグレーションファイルを実行する必要があります。
以下のコマンドで実行します。

```console:ターミナル
rails db:migrate
```

##バリデーションの設定
<details><summary>バリデーションとは</summary>
値がデータベースに保存される前に、そのデータが正しいかどうかを検証する仕組みをといいます。
</details>

ユーザーの新規登録をする際に、ユーザー名が何もない状態で登録できてしまう事を防ぐため、
nameカラムにバリデーションを設定します。models/user.rbに以下のコードを追加してください。

```ruby:app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  --- 一行追加---
  validates :name, presence: true, length: { maximum: 20 }
  --- ここまで ---
end
```

presence: trueは値が空ではないということ確かめるバリデーションです。
また、length: { maximum: 20 }は値の文字数が最大20文字までということを表すバリデーションです。
つまりこの場合、登録するユーザーは名前必須、かつ20文字以内で入力しないといけません。

##nameカラムを保存できるようにする
デフォルトだとメールアドレスとパスワードだけパラメータを受け取るようにストロングパラメーターが設定されています。

<details><summary>ストロングパラメーターとは</summary>
指定していないパラメーターを受け取るのを禁止します。
外部に公開する必要のない情報を誤って公開してしまう可能性が生じるため、
そのような事態を防ぐために行います。
</details>

今回nameカラムを保存できるようにストロングパラメーターを追記します。

```ruby:app/models/user.rb
class ApplicationController < ActionController::Base

--- 追加 ---
  protect_from_forgery with: :exception           #クロスサイトリクエストフォージェリ (CSRF)への対応策

  before_action :authenticate_user!               #ユーザーがログインしているかどうか確認
  before_action :configure_permitted_parameters, if: :devise_controller?
                                                  #devise_controllerを使うときしか処理しない

  protected

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
      devise_parameter_sanitizer.permit(:account_update, keys: [:name])
    end
--- ここまで追加 ---
end
```

`protect_from_forgery with: :exception`というコードはクロスサイトリクエストフォージェリ (CSRF)への対応策のコードです。
クロスサイトリクエストフォージェリー（CSRF）とは利用者の意図しないWebアプリケーション上の処理実行される攻撃手法のことだそうです。

▼クロスサイトリクエストフォージェリー（CSRF）についての参考

https://qiita.com/wanko5296/items/142b5b82485b0196a2da#:~:text=%E4%B8%80%E8%A8%80%E3%81%A7%E3%81%BE%E3%81%A8%E3%82%81%E3%82%8B%E3%81%A8,%E6%94%BB%E6%92%83%E6%96%B9%E6%B3%95%E3%81%AE%E3%81%93%E3%81%A8%E3%81%A7%E3%81%99%E3%80%82


またApplicationコントローラーは全てのコントローラーが読まれる前に必ず読まれるコントローラーです。
例えばhomeコントローラーのindexアクションが読まれる前にApplicationコントローラーが読まれます。

ただ、nameカラムを保存できるようにする記述はサインアップやアカウントをアップデートするときだけにしか必要がありません。

なので、`before_action :configure_permitted_parameters, if: :devise_controller?`と記載することで、`configure_permitted_parameters`というメソッドは、devise_controllerを使うときしか処理しないということをApplicationコントローラーを読み込む前に判断します。

##サインアップ画面のビューを変更する
生成されたビューのままだと下記画像のようにnameの入力フォームが存在しません。

![Qiita【devise_7】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/c80c41b3-2926-d4b7-1471-911d3aa130da.png)

下記のようにコードを追加します。

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

  <div class="field">
    <%= f.label :password %>
    <% if @minimum_password_length %>
    <em>(<%= @minimum_password_length %> characters minimum)</em>
    <% end %><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
  </div>

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

  <div class="actions">
    <%= f.submit "Sign up" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>

```

nameの入力フォームが追加されました。

![Qiita【devise_8】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/ddcb606c-c1cb-c9be-a622-f3c102dc5fff.png)

以上で、終了です。

Deviseを使うことにより手軽にユーザー認証機能を実装できます。
また、カラムを追加して入力フォームを充実させたり、モデルのモジュールの設定を変えることで、一定回数サインインを失敗するとアカウントをロックしたり・TwitterやFacebookなどの認証を追加できるようになるようです。
また、別の機会に学ぼうと思います。



##参考

https://github.com/heartcombo/devise

https://qiita.com/wanko5296/items/142b5b82485b0196a2da#:~:text=%E4%B8%80%E8%A8%80%E3%81%A7%E3%81%BE%E3%81%A8%E3%82%81%E3%82%8B%E3%81%A8,%E6%94%BB%E6%92%83%E6%96%B9%E6%B3%95%E3%81%AE%E3%81%93%E3%81%A8%E3%81%A7%E3%81%99%E3%80%82

https://qiita.com/cigalecigales/items/f4274088f20832252374