ログイン機能の実装【Rails】

#はじめに

現在、転職活動用のポートフォリオ作成のため、補助金などに関する記事の閲覧・検索アプリケーションを作成しております。その際に実装したユーザー管理機能（deviseの導入）をアウトプットのため記載していきます。記事初投稿になります。

環境：Rails 6.0


#1.deviseの導入

```ruby:Gemfile
gem 'devise'
```

を記述後、ターミナルにて

```ruby:ターミナル
% bundle install
% rails g devise:install
```

のコマンドを実行し、ライブラリをインストールします。

#2.モデルの作成

```ruby:ターミナル
% rails g devise user
```

のコマンドにて、モデルとマイグレーションの生成やルーティングの設定を行います。

#3.テーブルの作成

先ほど生成したマイグレーションファイルを使用してテーブルを作成します。

```ruby:...._devise_create_users.rb

class DeviseCreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string  :first_name,         null: false
      t.string  :last_name,          null: false
      t.string  :first_name_kana,    null: false
      t.string  :last_name_kana,     null: false 
      t.string  :email,              null: false, default: "", unique: true
      t.string  :encrypted_password, null: false, default: ""
      t.integer :state_id,           null: false
      t.string  :phone_number,       null: false
      t.date    :birth_day,          null: false
      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      # t.integer  :sign_in_count, default: 0, null: false
      # t.datetime :current_sign_in_at
      # t.datetime :last_sign_in_at
      # t.string   :current_sign_in_ip
      # t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_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
```

デフォルトでemailとpasswordのカラムは作成されているので、そのほか必要に応じて記載します（first_nameやbirth_dayなど）。


```ruby:ターミナル
% rails db:migrate
```

を実行し、usersテーブルが作成できる。

#4.モデルの編集

```ruby:app/models/user.rb
class User < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :state
  has_many :sns_credentials, dependent: :destroy

  devise :database_authenticatable, :registerable,
  :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:facebook, :google_oauth2]
  
  validates :first_name, :last_name, :first_name_kana, :last_name_kana, :state_id, :phone_number, :birth_day, presence: true
  PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i.freeze
  validates_format_of :password, with: PASSWORD_REGEX, message: 'には英字と数字の両方を含めて設定してください'
  validates :first_name, format: { with: /\A[ぁ-んァ-ン一-龥]/, message: 'は全角で入力してください' }
  validates :last_name, format: { with: /\A[ぁ-んァ-ン一-龥]/, message: 'は全角で入力してください' }
  validates :first_name_kana, format: { with: /\A[ァ-ヶー－]+\z/, message: 'は全角カナで入力してください' }
  validates :last_name_kana,  presence: true, format: { with: /\A[ァ-ヶー－]+\z/, message: 'は全角カナで入力してください' }
  validates :phone_number, format: { with: /\A\d{11}\z/, message: 'は数字のみで入力してください' }

#中略
```

こちらにバリデーションやアソシエーションを追記していきます。

#5.ビューファイルの編集

```ruby:index.html.erb
<header>

#中略
<%# ユーザーがログインしているとき %>
    <% elsif user_signed_in? %>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item login-user">ようこそ、<%= current_user.last_name %>さん！</li>
      </ul>
      <ul class="navbar-nav ml-auto">
        <li class="nav-item"><%= link_to '記事一覧', root_path %></li>
        <li class="nav-item"><%= link_to 'マイページ', "#" %></li>
        <li class="nav-item"><%= link_to 'ログアウト', destroy_user_session_path, method: :delete %></li>
      </ul>
    </div>
<%# ログインしていないとき %>
    <% else %>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto">
        <li class="nav-item"><%= link_to '記事一覧', root_path %></li>
        <li class="nav-item"><%= link_to '新規登録', new_user_registration_path %></li>
        <li class="nav-item"><%= link_to 'ログイン', new_user_session_path %></li>
      </ul>
    </div>
    <% end %>
  </nav>
  </div>
</header>
```

今回はログインしている場合としていない場合でビューファイルを分けています。

#6.ストロングパラメーターの設定

先ほどマイグレーションファイルでも記述しましたが、ユーザー情報のカラムはemailとpasswordがデフォルトで入っており、その他の任意の情報（ユーザー名など）は追記する必要があります。その際に新たな情報を渡すためにストロングパラメーターも編集しなければならないですが、deviseに関しては、処理を行うコントローラーがGemの中に記述されており、編集することができません。そのためdeviseのコントローラーにストロングパラメーターを反映する方法として、devise_parameter_sanitizerメソッドを使用しました。

```ruby: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: [:first_name, :last_name, :first_name_kana, :last_name_kana, :state_id, :phone_number, :birth_day])
  end
end
```

全てのコントローラーが継承しているファイルである、application_controller.rbファイルに記述しています。deviseの処理を行うコントローラーはGemの中に記述されており編集できないため、本ファイルに定義しています。

#7.最後に

一通りの実装方法を記述してきましたが、不明な点や間違っている点がありましたら、ご指摘いただけると幸いです。今後はdevise実装から管理者機能の追加、SNS認証の導入も行っていますので、そのアウトプットもできたらと思っております。