Rails 基礎 Part 06 -- devise でログインをした上で、API UT を叩く
Tags: ruby, rails, devise
Published: 2023-08-13 12:29:56


## why

Kotlin で API を作った時、ログイン機能まで作らなかった。Rails では作って、認証認可に強くなりたい。

---

## ライブラリ選定

devise という gem を使う。
一通り機能が揃っているらしい。


新規登録でお礼メールや、パスワードリセットなど。

https://github.com/heartcombo/devise#getting-started

---

---

# devise 活用

---
---

## devise をプロジェクトに入れる

https://github.com/heartcombo/devise#getting-started

```ruby
bundle add devise
```

bundle add で Gemfile に書き込み

---

## devise の設定を書き込む

```ruby
rails generate devise:install
```

rails generate で設定を開始する。

設定値がデフォルトで、設定ファイルが生成される。

* config/initializers/devise.rb
* config/environments/development.rb
* config/locales/devise.en.yml
* config/routes.rb

など。
パスワードリセットのメールのリンク先などが設定できる。

----

## User モデルと Migration ファイルの生成

devise を使って簡単に Model が作成できる。

```php
rails generate devise User 
      invoke  active_record
      create    db/migrate/20230813062406_devise_create_users.rb
      create    app/models/user.rb
      invoke    rspec
Migrations are pending. To resolve this issue, run:

        bin/rails db:migrate RAILS_ENV=development
```

これで models/user.rb ができる

```ruby
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
end
```

また、migration ファイルもできる

```ruby
class AddDeviseToUsers < ActiveRecord::Migration[7.0]
  def self.up
    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
```

migration ファイルにはコメントアウトされている行もある

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

      ## 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
```

これらのコメントアウトを外すと、最後のログインの情報を保存したり、頻繁なログイン失敗をロックしたりできる。

---

## schema

同様に schema.rb をみると users が追加されている

```ruby
  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end
```

---
---

# 既存の bankTransaction コントローラーの Rspec にログインを導入する

bankTransaction でログインを入れる

---

## rails_helper.rb に device の読み込み設定を記載

rspec を動かす時には、rails_helper が先に動く。
なので、rails_helper に設定を書いておけば、rspec で動いてくれる。

```ruby
  config.include FactoryBot::Syntax::Methods
  config.include Devise::Test::IntegrationHelpers, type: :controller
  config.include Devise::Test::ControllerHelpers, type: :controller
```

https://github.com/heartcombo/devise#test-helpers

---

## 実際に動かす

rspec --fail-fast を使うと、落ちたところで止まってくれるので便利。

```ruby
class BankTransactionsController < ApplicationController

  before_action :authenticate_user!
```

実装のコントローラーに認証がなかったので、コントローラーが動く前に、ログインしていなければリダイレクトに飛ばす処理を入れる

```ruby
  context 'ログインしているとき' do
    before do
      user_email = "kaede0902@gmail.com"
      user = User.find_by(email: user_email) || 
        FactoryBot.create(:user, email: user_email)

      sign_in user
      # spec/factories/bank_tranksactions.rb の内容が実行される
      FactoryBot.create(:bank_transaction)
    end
```

get リクエストの前に、指定のメールアドレスでユーザーを検索。

ユーザーがあればそのユーザーのインスタンスを取得。
ユーザーがなければそのユーザーを登録。

そしてそのユーザーでログイン。
ログインしている状態でコントローラーを叩く。

```
kaede0902@V bank_transactions_api % rspec --fail-fast

BankTransactionsController
  ログインしているとき
    GET #index
      取引明細の口座番号が正しく取得できること
      取引明細の金額が正しく取得できること
      取引明細の明細名が正しく取得できること
    POST #create
      取引データが作成できること

Finished in 0.11026 seconds (files took 1.74 seconds to load)
4 examples, 0 failures
```

これでログイン認証した上で、API UT を動かせた！

---

## 伸び代

ログインしていない時の挙動をテストする。

API なのでリダイレクトにはしないほうが自然