[初心者] deviseを使ってログイン機能を実装してみよう

# はじめに
railsのアプリケーションにログイン機能を実装したい、deviseって言うgemがあるみたいだけど初めてでどうやって使うんだ？という方向けに簡単なアプリケーションを作成しながら解説したいと思います。チュートリアル的に見てもらえると幸いです。

実際にdeviseを使い始めるのは３からなので、そこから見てもらっても大丈夫だと思います。

# 完成版サンプル

**未ログイン時の画面**
![スクリーンショット 2018-10-27 11.49.03.png](https://qiita-image-store.s3.amazonaws.com/0/307279/fa23ad30-acaf-c68e-423f-f8a5790eac1f.png)
未ログイン時は"現在ログインしていません"と表示されログインと新規登録ができる。

**ログイン時の画面**
![スクリーンショット 2018-10-27 11.50.16.png](https://qiita-image-store.s3.amazonaws.com/0/307279/b9d5b27f-8c23-a260-b29d-012779194fc6.png)

ログイン時には新規登録時に登録したユーザー名とメールアドレスが表示されログアウトができる。

※アプリケーションの機能は最低限に絞っています。

# 環境
Rails  5.1.6
MySQL  5.6.4(使ってる環境に応じて読み替えてください)
devise 4.5.0

基本的に記事投稿時の最新版をそのまま使用しています。

2022/06/17 追記
Rails6でも以下手順で大丈夫でした。

# そもそもdeviseとは？
ログイン機能やユーザー登録機能をとても簡単に実装することができるgem。
この記事がめちゃくちゃ詳しい：[[*Rails*] deviseの使い方（rails5版）](https://qiita.com/cigalecigales/items/f4274088f20832252374 "[*Rails*] deviseの使い方（rails5版）")

では実装していきましょう。

# 1.アプリケーションの作成
とりあえずアプリケーションを作成しましょう。以下のコマンドを入力してください。

```
$ rails new login_app -d mysql
$ cd login_app
```
DBは今回はMySQLを利用しています。環境に合わせて読み替えてください。


# 2.アプリケーションの雛形作成
ルート、コントローラーの設定をしていきます。以下のコマンドを入力してください。

```
$ bundle exec rake db:create # アプリのDB作成
$ rails g controller comments index # コントローラーの作成 ついでにアクションとビューも
```

` rails g controller コントローラー名 アクション名 `　とコマンドを打ち込むことによってコントローラの作成と同時に指定したアクションとルートの設定とビューファイルの作成も行えます。
ただしrootは設定してくれないので手動で設定します。

```ruby:login_app/config/routes.rb
Rails.application.routes.draw do
  root 'comments#index' # ここを追記します
  get 'comments/index' # 自動で設定されたルーティング
end
```

ここで `rails s` でアプリを起動して http://localhost:3000/ に接続してみましょう。上手く設定できていれば以下のような画面になっているはずです。

![スクリーンショット 2018-10-27 12.57.13.png](https://qiita-image-store.s3.amazonaws.com/0/307279/e473bc14-4d8a-bb6b-d8ee-b6b9e382cf30.png)

このビューはコントローラの作成時に一緒に作ったビューです。deviseの導入後はこのファイルを編集していきます。


# 3.deviseの導入

いよいよ本番です。アプリケーションにdeviceを導入しましょう。まずgemfileを編集します。

```ruby:login_app/gemfile
gem 'devise' # gemfileの一番下に記述
```

gemfileに記述ができたら`bundle install`を行いアプリにdeviseをインストールしましょう。
インストールが終わったら`rails s`をしてサーバーを立て直しましょう。


次はdiviseを利用するのに必要なファイルを作成しましょう。以下のコマンドを入力してください。

```
$ rails g devise:install # deviseの設定ファイルを作成する
```

上記のコマンドはdeviseの設定ファイルを作成するdevise専用のコマンドです。ここで作成されたファイルは今回は触らないので気にしなくて大丈夫です。

ファイルを作成できたらログイン機能用のモデル(テーブル)の作成を行います。以下のコマンドを入力してください。

```
$ rails g devise user #ログイン機能用のモデルを作成
$ rake db:migrate #マイグレート
```
`rails g devise テーブル名`はdeviseでログイン機能をつける概念のモデルを作成する際に利用するコマンドです。このコマンドによってログイン機能のために必要なカラムがモデルに追加されるマイグレーションファイルなどが生成されます。

このコマンドを実行すると以下のようなDBが作成されます。

```
mysql> desc users;
+------------------------+--------------+------+-----+---------+----------------+
| Field                  | Type         | Null | Key | Default | Extra          |
+------------------------+--------------+------+-----+---------+----------------+
| id                     | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| email                  | varchar(255) | NO   | UNI |         |                |
| encrypted_password     | varchar(255) | NO   |     |         |                |
| reset_password_token   | varchar(255) | YES  | UNI | NULL    |                |
| reset_password_sent_at | datetime     | YES  |     | NULL    |                |
| remember_created_at    | datetime     | YES  |     | NULL    |                |
| created_at             | datetime     | NO   |     | NULL    |                |
| updated_at             | datetime     | NO   |     | NULL    |                |
+------------------------+--------------+------+-----+---------+----------------+
```

ではビューの実装に取り掛かっていきます。

# 4.アプリケーションのビューの実装
ユーザー新規要録画面やログイン画面はコマンドでまとめて作成できます。

```
$ rails g devise:views #ログイン機能に必要なビューファイルをまとめて作成
```
上記のコマンドを実行すると沢山ビューファイルが作成されますが、重要なのは以下の２つのファイルです。

新規登録画面：app/views/devise/registrations/new.html.erb
ログイン画面：app/views/devise/sessions/new.html.erb

基本的にはこのファイルを編集していけばログイン機能の実装は可能だと思います。
ここでもう一度`rails s`をしてサーバーを再起動しましょう。

ではトップページのビューを編集してログイン画面に遷移できるようにしましょう。views/comments/index.html.erb ファイルを以下のように編集します。元からある記述は消して大丈夫です。

```erb:views/comments/index.html.erb
<h1>ログインアプリ</h1>

<% if user_signed_in? %> <!-- ユーザーがログインしているか調べる -->
  <!-- ユーザーがログインしていた時の処理 -->

  <h4> メールアドレス： <%= current_user.email %> </h4>
  <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> <!-- ログアウトをする -->
<% else %>
  <!-- ユーザーがログインしていなかった時の処理 -->
  <h2> 現在ログインしていません </h2>
  <%= link_to "ログイン", new_user_session_path, class: 'post' %> <!-- ログイン画面に移行する -->
  <%= link_to "新規登録", new_user_registration_path, class: 'post' %> <!-- 新規登録画面に移行する -->
<% end %>
```

`user_signed_in?`とはdiviseをアプリに導入すると使えるようになるメソッドで、ユーザーがログインしているかどうか調べることができるメソッドです。ログインしている場合にはtrueを返し、ログインしていない場合にはfalseを返します。
今回の場合はユーザーがログインしていればメールアドレスを表示し、ログアウトのリンクを出します。ログインをしていなければ"現在ログインしていません"と表示し、ログインと新規登録画面のリンクを出します。

`current_user`は今ログインしているユーザーの情報が入っており、`current_user.email`とすると今ログインしているユーザーのメールアドレスが取得できます。`current_user.カラム名`は良く使うので覚えておくと便利です。


記述ができたら http://localhost:3000/ に接続してみてください。完成版サンプルの未ログイン時の画面と同じ画面になっていると思います。

さて、実際に機能を試してみましょう。とりあえず新規登録を行ってユーザーを新しく作成します。
画面の新規登録をクリックしてEメールとパスワードを入力して実際に登録をしてみましょう。

![スクリーンショット 2018-10-29 11.46.53.png](https://qiita-image-store.s3.amazonaws.com/0/307279/f6d0361a-b430-a846-a8f2-47d20e2fd297.png)



すると以下の画面に切り替わったと思います。

![スクリーンショット 2018-10-29 11.32.28.png](https://qiita-image-store.s3.amazonaws.com/0/307279/7e112ee7-e4df-ba8a-eb53-ab2e85574eb6.png)

先ほど新規登録画面で登録したメールアドレスが表示されています。これでログイン機能の実装が完了しました！一度ログアウトをして今度はログインしてちゃんと登録されているか試してみましょう！

しかし、ログイン機能は完成しましたが**名前が登録されていません。**
これは上にあるusersテーブルを見ればわかりますが名前に当たるカラムがありません。そもそも新規登録画面で名前を入力するフォーム欄が存在しません。**diviseは初期状態ではメールアドレスとパスワードしか登録できない**のです(多分拡張性を持たせる為だと思います)。
なので名前を登録できるように機能を追加しましょう。


# 5.新規登録時に名前を入力できるようにする

必要な作業は4つあります。

・usersテーブルにnameカラムを追加する
・新規登録画面に名前を入力できる欄を追加する
・ストロングパラメータで名前を保存できるようにする
・メインページで登録した名前が表示されるようにする

ではusersテーブルにnameカラムを追加する所からやっていきます。以下のコマンドを入力してください。

```
$ rails g migration AddNameToUsers name:string # usersテーブルにnameカラムをstring型で追加するマイグレーションファイルを作成
$ rake db:migrate # マイグレート
```

これでusersテーブルにnameカラムが追加されました。次は新規登録画面を編集して名前を入力できるようにフォーム欄を追加します。
新規登録画面は app/views/devise/registrations/new.html.erb に存在しています。

```erb:login_app/app/views/devise/registrations/new.html.erb
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

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

  <!-- ここから追加してください -->
  <div class="field">
    <%= f.label :name %> <br />
    <%= f.text_field :name %>
  </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" %>

```

編集が終わったら新規登録画面に行ってみましょう。以下のように名前を入力する欄が追加されているはずです。

![スクリーンショット 2018-10-29 13.52.08.png](https://qiita-image-store.s3.amazonaws.com/0/307279/16d3cb00-0925-7798-bb60-8d9e3517475a.png)

さてこれで名前が入力できるようになったのですが**実はこのままでは名前はDBに保存されません。**何故なら**deviseでは初期状態で新規登録時にメールアドレスとパスワードのみを受け取るようにストロングパラメーターが設定してあるから**です。
なのでdeviseのストロングパラメーターを編集して名前も受け取るようにしなければいけないのですが、**deviseのストロングパラメーターはdeviseのgem内に記述されているので直接編集することができません。**
じゃあどうするのかと言うとdeviseが提供している`configure_permitted_parameters`メソッドを利用することになります。
このメソッドはdeviseのストロングパラメーターを追加できるメソッドで、`application_controller`に記述をします。以下のように編集を行ってください。

```ruby:login_app/app/controllers/application_controller
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  # ここから追加します
  before_action :configure_permitted_parameters, if: :devise_controller?

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) # 新規登録時(sign_up時)にnameというキーのパラメーターを追加で許可する
  end
  # ここまで追加します
end

```
これで新規登録時に名前が登録できるようになりました。最後にトップページを編集して登録した名前を表示されるようにしましょう。

```erb:views/comments/index.html.erb
<h1>ログインアプリ</h1>

<% if user_signed_in? %> <!-- ユーザーがログインしているか調べる -->
  <!-- ユーザーがログインしていた時の処理 -->
  <h2> 現在 <%= current_user.name %> さんがログインしています </h2> <!-- ここを追加します -->
  <h4> メールアドレス： <%= current_user.email %> </h4>
  <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> <!-- ログアウトをする -->
<% else %>
  <!-- ユーザーがログインしていなかった時の処理 -->
  <h2> 現在ログインしていません </h2>
  <%= link_to "ログイン", new_user_session_path, class: 'post' %> <!-- ログイン画面に移行する -->
  <%= link_to "新規登録", new_user_registration_path, class: 'post' %> <!-- 新規登録画面に移行する -->
<% end %>

```
名前の表示を行うのは`current_user.name`です。今ログインしているユーザー(current_user)の名前(name)をDBから取得しています。

これで実装完了です！お疲れ様でした！

# まとめ
以下のメソッドは良く使うので覚えておきましょう。

`user_signed_in?`：ユーザーがログインしているか調べる。ログインしているかどうかでビューを変えたい時などに利用する。
`current_user.カラム名`：現在ログインしているユーザーのデータをDBから取ってくる。
`configure_permitted_parameters`：ストロングパラメーターの許可を追加する。

またメソッド以外では以下のことを覚えておくと便利だと思います。

`rails g devise:views`：ログイン機能に必要なビューファイルをまとめて作成するコマンド
新規登録画面：app/views/devise/registrations/new.html.erb
ログイン画面：app/views/devise/sessions/new.html.erb

<%= link_to "ログイン", new_user_session_path %>
ログイン画面に移行するリンク。urlだと`/users/sign_in`となる。

<%= link_to "新規登録", new_user_registration_path %>
新規登録画面に移行するリンク。urlだと`/users/sign_up`となる。

<%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
ログアウトするリンク。urlだと`/users/sign_out`となる。

# エラーが出たら
再起動をすれば治る可能性があります。`rails s` を試してみてください。

# 終わりに
以上が基本的なdeviseの使い方でした。良かったら参考にしてみてください。また、これはdeviseの基本的な機能なので色々調べてみると面白いと思います。