🔰【初学者用】deviseを使ってユーザー管理機能を実装しよう！【Ruby on Rails】

## はじめに
プログラミング初学者の私がアウトプットとこれから学習される皆様の参考になればと思い投稿しています。
まだ、マークダウン記法も不慣れな初学者ですので、間違い等があれば指摘いただけると幸いです。

## この記事を見てできるようになること
Ruby on Railsのgemであるdeviseを使用して、ユーザー管理機能を実装できるようになります！

## deviseとは？
ユーザー管理機能（例：ログイン、ログアウト、新規登録）を簡単に実装するためのGemです。

## deviseの導入
まずGemfileを編集します。追記する場所はGemfileの最後の行で構いません。
```:Gemfile
gem 'devise'
```
:::note warn
**⚠注意**
**device**としないこと!
私はこれでかなりの時間を消費しました\:cry:
:::

使用するアプリディレクトリを開き以下のコマンドでgemをインストールします。

```:ターミナル
bundle install
```
次にローカルサーバーを起動or再起動させます。
サーバーを起動していなかった場合↓（起動）
```:ターミナル
rails s
```
元々サーバーを起動していた場合↓（再起動）
```:ターミナル
control + C
rails s　 
````
これでdeviseの導入は完了です！

## deviseの設定ファイルを作成
以下のコマンドを実行してください。
```:ターミナル
rails g devise:install
```
上記コマンドを実行することで、deviseに関する設定ファイルを自動生成してくれます。
これでdeviseの設定ファイルの作成は完了です！

## deviseのuserモデルを作成
続いてUserモデルを作成していきますがここで注意点があります。

:::note warn
**deviseを使用する場合、通常のモデル作成方法とは異なります。**
:::

通常モデルを作成する場合は`rails g model user`のように実行しますが、deviseを利用する場合は以下のように記述し実行します。以下のコマンドを実行してください。
```:ターミナル
rails g devise　user
```
上記コマンドを実行することでrails g deviseコマンドという、モデルとマイグレーションの作成やルーティング設定をまとめてしてくれます。
モデルとマイグレーションの作成やルーティング設定↓

```config/routes.rb
Rails.application.routes.draw do
  devise_for :users #追加された記述
  root to: 'tweets#index'
  resources :tweets
end
```
```db/migrate/20XXXXXXXXX_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration[6.0]
 def change
   create_table :users do |t|
     ## Database authenticatable
     t.string :email,              null: false, default: ""
     t.string :encrypted_password, null: false, default: ""

     ## Recoverable
     t.string   :reset_password_token
     t.datetime :reset_password_sent_at

     ## Rememberable
     t.datetime :remember_created_at

     # 省略

     t.timestamps null: false
   end

   add_index :users, :email,                unique: true
   add_index :users, :reset_password_token, unique: true
   # add_index :users, :confirmation_token,   unique: true
   # add_index :users, :unlock_token,         unique: true
 end
end
```

デフォルトでカラムが設定されていますが、新たにカラムが必要であれば自身で記述します。
新しいカラムを追加した場合、マイグレーションを忘れずに実行してください。
```:ターミナル
% rails db:migrate
```
ちなみに`rails g migration Addカラム名To追加先テーブル名 追加するカラム名:型`とすることで、テーブルにカラムを追加する際に必要なコードが記述された状態で、マイグレーションが生成されます。
<details><summary>サンプルコード</summary>

```:ターミナル
% rails g migration AddNicknameToUsers name:string
```

※上記は一例です。必ず実行しなければならないわけではありません。
</details>

## deviseのビューを作成
続いてビューファイルを作成していきます。
以下のコマンドを実行してください。
```:ターミナル
% rails g devise:views
```
上記コマンドでdevise用のビューファイルが生成されました
サインアップ画面:`app/views/devise/registrations/new.html.erb`
ログイン画面:`app/views/devise/sessions/new.html.erb`
作成されていることが確認できたら自分好みに編集しましょう！

## deviseのコントローラー
deviseのコントローラーは**直接編集できません。** 理由はdeviseのコントローラーがGemに記載されているからです。
そのため、編集ができる`application_controller.rb`にストロングパラメーターを定義し、その処理を読み込ませます。
一例としてはこのような記述↓
```app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  private
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end
```
まずは２行目から説明します。
```app/controllers/application_controller.rb
before_action :configure_permitted_parameters, if: :devise_controller?
```
`before_action`の記述で各コントローラーよりも先に指定のアクションを行ってくれます。
`:configure_permitted_parameters`の記述はメソッド名です。慣習的にこのメソッド名で定義することが多いため使用しています。
`if: :devise_controller?`の記述でdeviseのコントローラに対してのみメソッドの処理を行うようにします。なお、`:devise_controller?`はdeviseのヘルパーメソッドです。

次に５行目〜７行目を説明します。
```app/controllers/application_controller.rb
def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
end
```
`devise_parameter_sanitizer`はdeviseにおけるparamsのようなメソッドです。「ログイン」「新規登録」などのリクエストからパラメーターを取得できます。
以下のように記述します。
```
devise_parameter_sanitizer.permit(:deviseの処理名, keys: [:許可するキー])
```
devise処理名の一例
| 処理名           |役割                 |         
|:----------------|:-------------------|
| :sign_in        | ログイン処理          |
| :sign_up        | 新規登録処理         |
| :account_update | アカウント情報更新の処理 |

記述を終えたら実際にユーザーを登録してみましょう！

## ログインの有無で表示を変える
ログインの有無で表示を変えるにはuser_signed_in?メソッドを使用します。このメソッドはログインしていればtrue、ログインしていなければfalseを返します。
使用例↓
```views/layouts/application.html.erb
<% if user_signed_in? %>
  <div class="">
    <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
    <%= link_to "投稿する", new_tweet_path, class: "post" %>
  </div>
<% else %>
  <div class="">
    <%= link_to "ログイン", new_user_session_path, class: "post" %>
    <%= link_to "新規登録", new_user_registration_path, class: "post" %>
  </div>
<% end %>
```
この記述の場合、ログインしていればログアウト・投稿する、ログインしていなければログイン・新規登録を表示します。

## ログインしてないユーザーをリダイレクトする
ログインしていないユーザーをリダイレクトするには以下のような記述を行います。
```app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
  before_action :move_to_index, except: [:index, :show]
〜中略〜
  private
  def move_to_index
    unless user_signed_in?
      redirect_to action: :index
    end
  end
end
```
まず2行目の`except: [:index, :show]`です。expectはbefore_actionで使用できるオプションで、除外するという意味があり、指定したアクションに対しては事前の処理が実行されなくなります。この場合だと、indexとshowアクションが除外の対象になります。
続いて6行目の`unless user_signed_in?`です。unlessは条件式がfalseの時に処理が実行されます。この記述の場合user_signed_in?を使用しているので、ユーザーがログインしていない場合処理を行うということになります。
最後に7行目`redirect_to action: :index`です。で以下のように記述します。
```
redirect_to action: :リダイレクト先となるアクション名
```
この記述によりリダイレクト先のを指定できます。

上記記述をまとめると**ログインしていないユーザーはindexアクションにリダイレクトされるが、indexアクションとshowアクションはmove_to_indexの対象外である。**

ということになります。

# まとめ
以上がdeviseを用いたユーザー管理機能の実装方法でした。
これだけで簡単な流れは抑えられたはず！

※プログラミング初学者が投稿しております。訂正等がありましたら、コメントよろしくお願いします。