【Rails】ログイン機能をGem 'devise'で実装

こんにちは。
早く駆け出したい修行僧です。

今回は、Gemの <font color='#00bfff'>'devise'</font> を使ったログイン機能を学んだので、
こちらにアウトプットさせていただきます。

尚、「それは違うよ」など訂正箇所がございましたら、
愛のあるご指摘を頂けたら幸いです。


# 環境
macOS Monterey(M1) 12.2.1
ruby 3.1.0
Rails 6.1.4.6
devise 4.8.1

# 'devise'とは
特定のページを閲覧したりユーザに制限をかけたりするためには**ログイン認証**が必要となってきます。ログイン認証とはログインやログアウトの機能を指します。
そして、それらは新規登録をしないと始まりません。そんな機能を簡単に実装してくれる優れたgemが <font color='#00bfff'>'devise'</font> です。

# インストール
`rails new` でアプリ作成済みであることを前提とします。
まずは導入したいアプリケーションのGemfileに以下のコードを挿入します。

```ruby:Gemfile
gem 'devise'
```
挿入ができましたら次はターミナルにて以下のコマンドを実行してgemをインストールします。

```:terminal
$ bundle install
```
次はdeviseを使用するための設定ファイルをdevise専用コマンドで作成する必要があります。
以下のコマンドをターミナルにて実行します。('g'は'generate'の省略です)

```:terminal
$ rails g devise:install
```

上記のコマンドを実行すると、以下のような表示がされたらとりあえず成功です。

```:terminal
===============================================================================

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"
     
     * Not required for API-only Applications *

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views
       
     * Not required *

===============================================================================

```

何やらたくさんの英文が出てきて一瞬驚かれると思いますが、一つずつ進めていきましょう。
### 1. 設定するファイルにデフォルトURLの指定
公式にもある通り、デフォルトのURLの指定が必要となります。設定するファイルは以下の引用にも記載されている `config/environments/development.rb` です。

>At this point, a number of instructions will appear in the console. Among these instructions, you'll need to set up the default URL options for the Devise mailer in each environment. Here is a possible configuration for config/environments/development.rb:
>引用：[公式リファレンス](https://github.com/heartcombo/devise#getting-started)

では具体的には何を指定するかは先ほどターミナルで出力された '1' に記載されています。

```ruby:config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```

### 2. ルートの設定
続いてルートの設定を行なっていきます。'devise'は新規登録完了後、指定のルートへ飛ぶ設定になっています。ですので、先ほどのメッセージに記載されている `config/routes.rb` ファイルに設定をしていきます。

```ruby:config/routes.rb
Rails.application.routes.draw do
  root "homes#index"
  get "/news", to: "news#news"
end
```

＊現時点で、まだページを作成されていない方は、 `rails g controller コントローラ名 index show` などで適当に作っておいても良いと思います。今回、筆者はindexとnewsのページを作成しております。

### 3. フラッシュメッセージをビューファイルに挿入する
フラッシュメッセージとはログインした際に、ヘッダー付近に「ログインしました」のようなメッセージを指します。Progateを既に学習された方は何となく見覚えがあるのではないでしょうか。
では、どこにフラッシュメッセージを挿入するかというと、こちらも先ほどのメッセージに記載されている `app/views/layouts/application.html.erb` へ挿入をしていきます。

```erb:app/views/layouts/application.html.erb
<!DOCTYPE html>

  <% # 省略 %>

  <body>
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
    
    <%= yield %>
  </body>
```

### 4. deviseのビューを作成する
最後にdeviseのviewを自分でカスタマイズするためには以下のコマンドを実行して作成されたファイルを編集していく必要があります。

```:terminal
$ rails g devise:views
```

実行した後、以下のような表示がされていれば成功です。

```:terminal
      create    app/views/devise/shared
      create    app/views/devise/shared/_error_messages.html.erb
      create    app/views/devise/shared/_links.html.erb
      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
      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

```

詳しく何のファイルなのか知りたい！っていう方は @cigalecigales さんの [記事](https://qiita.com/cigalecigales/items/16ce0a9a7e79b9c3974e#4-devise%E3%81%AEview%E3%82%92%E7%94%9F%E6%88%90) をご覧になっていただけると理解が深まると思います。

## モデルの作成
'devise'の設定が終わったら、今度はモデルを作成していきます。通常、モデルを作成する際は `rails g model MODEL` を実行すると思います。しかし、'devise'を使用する際は、'devise'専用のコマンドを実行してログイン機能に対応したモデルを作成します。
それでは、以下のコマンドを実行しましょう。

```:terminal
$ rails generate devise <任意のモデル名>
```

実行した後、以下のような表示がされていると思います。

```:terminal
      create    db/migrate/20220224141911_add_devise_to_users.rb
      insert    app/models/user.rb
       route  devise_for :users
```

そして `config/routes.rb` を確認してみると、 `devise_for :users` と自動でルーティングが設定されていることがわかります。

```ruby:
Rails.application.routes.draw do
  devise_for :users
  
  root "homes#index"
  get "/news", to: "news#news"
end
```

モデルが作成できたら、忘れないうちにマイグレーションを実行して、ログイン機能に必要なテーブルを作成しておきましょう。

```:terminal
$ rails db:migrate
```

# 最後に
たったこれだけの設定でログイン機能が実装できることは非常にありがたいことだと思います。
'devise'にはもっと便利な機能があるみたいなので、もっと触っていき自由に使いこなせるようになりたいです。(追記で更新もしていこうかなとも思っています)
最後までご覧になっていただきありがとうございます。

# 参考文献
[公式レファレンス](https://github.com/heartcombo/devise)
[[*Rails*] deviseの使い方（rails6版） - @cigalecigalesさん](https://qiita.com/cigalecigales/items/16ce0a9a7e79b9c3974e)
[【Rails】 deviseの使い方とは？ログイン認証機能を実装しよう](https://pikawaka.com/rails/devise)