Ruby on Rails のアプリケーションに、 devise を利用して認証機能を実装し、更に Google アカウントに連携した認証機能とテストコードを実装します。よくありがちなユーザー認証機能をdeviseを使いサクッと実装し、Googleを使ったSNS認証機能とテストコードを実装する方法について解説していきます。
動作環境
- PostgreSQL 12.1
- macOS Catalina
- Ruby 2.7.0
- Rails 6.0.7.2
全体の概要
本記事では、3つのステップで進めていきます。
- devise でサインイン機能を実装する
- OmniAuth で Google アカウント機能を実装する
- Omniauth のテストコードを実装する
1. deviseでサインイン機能を実装する
まずは、devise でサインイン機能を実装し、deviseとはどのような機能を持つGem(ライブラリ)なのかを掴みましょう。
本項は下記を参考にしました。
- Railsでユーザー認証機能を実装しよう~定番のgem「devise」活用法(1) (1/4):CodeZine(コードジン)
- Railsでユーザー認証機能を実装しよう~定番のgem「devise」活用法(2) (1/4):CodeZine(コードジン)
- [Rails] deviseの使い方(rails5版) - Qiita
- GitHub - heartcombo/devise: Flexible authentication solution for Rails with Warden.
deviseとは
まずはじめに、deviseについて解説します。deviseとはRailsアプリケーションに柔軟な認証機能を追加するためのライブラリです。
アプリケーションコードをほとんど書かなくても、認証に必要な機能を追加でき、とても便利です。
deviseを理解するには、下記の点を抑えておくと良いでしょう。
- Rails エンジンの仕組みを利用している
- 認証機能毎にモジュールがある
- 導入するだけで利用できるメソッドがある
Railsエンジンとは
deviseはRailsエンジンの仕組みを使ったGemだと説明しましたが、Railsエンジンとは何でしょうか?
エンジン (engine) は、ホストとなるRailsアプリケーションに機能を提供するミニチュア版Railsアプリケーションとみなせます。この場合、ホストとなるRailsアプリケーションは、実際にはエンジンに「ターボをかけた」ようなものにすぎず、Rails::ApplicationクラスはRails::Engineから多くの振る舞いを継承します。
すなわち、エンジンとアプリケーションは、細かな違いを除けばほぼ同じものであると考えていただいてよいでしょう。
とりあえずは Rails エンジンが、基本的な構成が Railsのアプリケーションと同様
、ということをとりあえずは抑えておけばよいでしょう。
モジュール一覧
deviseは認証機能毎に複数のモジュールに分かれています。認証と言ってもひつような機能はさまざまで、「ユーザーを新規に登録する」や「パスワードを忘れたらリセットする」、「メールアドレスにバリデーションを追加する」などの機能によって、モジュールがそれぞれ用意されているのです。モジュールの一覧は下記なので、ざっと目を通しておく程度で大丈夫です。
- Database Authenticatable
- ユーザー情報をハッシュにして、データベースに保存する
- Omniauthable
- Omniauth を使い外部サービスと連携したログインさせる
- Confirmable
- サインイン時にemailを送信して、アカウントがemailによる認証済みかを検証する
- Recoverable
- パスワードをリセットし、リセット用のURLを発行する
- Registable
- ユーザーが自身の情報の登録・編集・削除を可能にする
- Rememberable
- 保存されたCookie(PCに保存されるログイン情報のこと)から、リメンバーミー(ブラウザを閉じてもログインが有効)を可能にする
- Trackable
- サインインの回数やサインインのタイムスタンプ、IPアドレスなどの情報を保存する
- Timeoutable
- ログインから一定期間たったユーザーをタイムアウトさせる
- Validatable
- メールアドレスとパスワードのバリデーションを追加する
- Lockable
- 指定した回数ログインを失敗するとロックする
devise で使えるメソッド
deviseは導入するだけで使えるヘルパーメソッドがいくつか用意されています。
例えば、user_singed_in?
メソッドなどは、地道に実装しようとするとなかなかのコード行数になりますので、あらかじめ準備されていてとても便利です。
用意されているメソッドは、下記があります。
メソッド | 用途 |
---|---|
before_action :authenticate_user! | ユーザーが認証(ログイン済み)の場合のフィルター |
user_signed_in? | ユーザーがサインインしているかをの真偽値を返す |
current_user | サインインしているユーザーを取得する |
user_session | ユーザーのセッション情報にアクセスできる |
上記は User モデルの場合を記していますが、Memberモデルの場合は、下記のようになります。
before_action :authenticate_member!
member_signed_in?
current_member
member_session
アプリケーションを新規作成する
データベースに PostgreSQL を指定して、アプリケーションを作成します。作成できたら、データベースを作成しましょう。
$ mkdir devise
$ cd devise
$ rails new . -d postgresql
$ rails db:create
devise のセットアップをする
devise を追加する
次に、Gemfile
にdeviseを追加します。
devise は開発環境、テスト環境、プロダクション環境すべての環境で利用するので、Gemfile
の一番下に追加します。
gem 'devise'
Gemfile に追加したら下記のコマンドを実行しインストールします。
$ bundle install
devise をインストールする
次に、deviseの機能をRailsアプリケーションにインストールします。
この、インストールしに生成された2つのファイルと、セットアップ用のコメントは非常に重要なため、このあと詳しく見ていきます。
$ rails g devise:install
create config/initializers/devise.rb
create config/locales/devise.en.yml
===============================================================================
Some setup you must do manually if you haven't yet:
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.
2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:
root to: "home#index"
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>
4. You can copy Devise views (for customization) to your app by running:
rails g devise:views
===============================================================================
設定ファイルを確認する
config/initializers/devise.rb
は devise の各機能ごとの設定を記載するためのファイルです
翻訳ファイルを確認する
config/locales/devise.en.yml
は devise で用いるアプリケーションのビューのテキスト表示を記載するためのファイルです
ActionMailerの設定を追加する
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.
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
ルーティングを追加する
2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:
root to: "home#index"
ルートのURLを定義するように言われているので、config/routes.rb
に定義します。ここでは、Topsコントローラーのindexアクションを紐付けます。
root to: 'top#index'
flashメッセージを追加する
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>
<body>
<p class="notice"><%= notice %></p> # 追記
<p class="alert"><%= alert %></p> # 追記
<%= yield %>
</body>
ビューファイルを作成する
4. You can copy Devise views (for customization) to your app by running:
rails g devise:views
devise に用意されたgenerateコマンドを利用して、viewを作成します。
$ bin/rails g devise:views
作成されたviewを見るとおわかりかと思いますが、認証に必要な一通りのviewが一度に作成できてしまいます。素晴らしい。
Running via Spring preloader in process 72079
invoke Devise::Generators::SharedViewsGenerator
create app/views/devise/shared
create app/views/devise/shared/_error_messages.html.erb
create app/views/devise/shared/_links.html.erb
invoke form_for
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
invoke 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
User モデルを作成する
$ rails g devise User
マイグレーションファイルを確認、実行する
マイグレーションファイルには、deviseの各機能(module)ごとにカラムが記載されています。デフォルト設定のものはコメントアウトが外されており、デフォルトにない設定のものはコメントアウトされています
# frozen_string_literal: true
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
## Trackable
# t.integer :sign_in_count, default: 0, null: false
# t.datetime :current_sign_in_at
# t.datetime :last_sign_in_at
# t.inet :current_sign_in_ip
# t.inet :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
マイグレーションファイルの確認が終わったら、マイグレーションを実行します
$ rails db:migrate
ルーティングを確認する
先程追加したルートのルーティングに加え、deviseのルーティングが追加されています。具体的にどのようなURLが発行されているのか確認しましょう。
Rails.application.routes.draw do
devise_for :users
root to: 'top#index'
end
$ rails routes
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
user_registration PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
root GET / top#index
rails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create
rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create
rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create
rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create
rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create
rails_conductor_inbound_emails GET /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#index
POST /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#create
new_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/new(.:format) rails/conductor/action_mailbox/inbound_emails#new
edit_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id/edit(.:format) rails/conductor/action_mailbox/inbound_emails#edit
rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#show
PATCH /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update
PUT /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update
DELETE /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#destroy
rails_conductor_inbound_email_reroute POST /rails/conductor/action_mailbox/:inbound_email_id/reroute(.:format) rails/conductor/action_mailbox/reroutes#create
rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show
rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show
update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update
rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create
動作確認をする
上記では、URLがたくさん生成されていることを確認しました。ここでは試しに、sign_in
にアクセスし、devise の機能が有効になっているかを確認してみましょう。
localhost:3000/sign_in
にアクセスしてください
下記のような画面が表示されていれば成功です。
トップページを作成する
トップページ用のコントローラーを追加します。
$ rails g controller top index
早速、before_action :authenticate_user!|
を追加しましょう。
class TopController < ApplicationController
before_action :authenticate_user!, only: %i[index]
def index; end
end
トップページであるlocalhost:3000
にアクセスしようとすると、localhost:3000/users/sign_in
にリダイレクトされていれば大丈夫です。
Sign_up
からユーザー情報を登録し、ログインできるようになっているはずです。
2. OmniAuth で Google アカウント機能を実装する
さて、ここからは SNS認証機能を追加していきます。今回は、Googleアカウントを利用しましょう。
本項は、下記を参考にしました。
- RailsでSNS認証機能を実装しよう~定番gem「OmniAuth」活用法 (1/3):CodeZine(コードジン)
- GitHub - omniauth/omniauth: OmniAuth is a flexible authentication system utilizing Rack middleware.
- Railsでomniauth(google/facebook/)実装方法 - Qiita
OmniAuth とは
OmniAuthとは、外部サービスのアカウントを使った認証機能を提供する仕組みです。各外部サービスとのOauth認証機能をStragetyとして持っています。
Omniauthの仕組みを知る上では、下記の点を抑えておくと良いでしょう。
- Oauth2 による認証を提供している
- Rack ミドルウェアを利用している
- Strategy を管理している
Oauth2とは
アクセストークンの要求方法とそれに対する応答方法を標準化したものが OAuth 2.0 である
Rackとは
Rackは、RubyのWebアプリケーションに対して、モジュール化された最小限のインターフェイスを提供して、インターフェイスを広範囲に使えるようにします。RackはHTTPリクエストとレスポンスを可能なかぎり簡単な方法でラッピングすることで、Webサーバー、Webフレームワーク、その間に位置するソフトウェア (ミドルウェアと呼ばれています) のAPIを1つのメソッド呼び出しの形にまとめます。
Rackとは、HTTP通信に利用されているミドルウェアのことを言います。
Strategyとは
Strategyとは具体的な外部サービス(Probider)を指します。具体的なサービスとの関連付けは下記のようになっており、Strategyと同名のGemが提供されています。
Probider | Strategy |
---|---|
google-oauth2 | |
CLIENT_ID と CLIENT_SECRET の取得
今回は、Google APIを利用します。
Google Cloud Platform にアクセスし、My Project▼
をクリックします。
任意のプロジェクト名ここではdevise-omniauth
と入力し、作成をクリック。
OauthクライアントID をクリックします。なお、OAuthクライアントIDとは、ユーザーの情報にアクセスするためのサービス提供者に割り当てられた一意のIDのことです。
Userのタイプを選択します。組織内のみで利用する場合は、内部
を、Googleアカウントを持つすべてのユーザーが利用できるようにする場合は、外部
を選択します。
任意のアプリケーション名を記載し、下までスクロールして保存
をクリックします。
OAuth クライアントID作成の画面では、任意の名前を入力し、承認済みリダイレクトURL(コールバックURL)
に下記を記載します。間違えないよう、コピペすることをおすすめします。
なお、コールバックURLとは、認証後に外部サービス(ここでは、Google)認証ページからリダイレクトされる自身のアプリケーションのURLを指しています。
http://localhost:3000/users/auth/google_oauth2/callback
すると、クライアントIDとクライアントシークレットが発行されますので、テキストファイルなどにして保存してください。一度だけしか発行されないため、取り扱いには厳重注意をしてください。
なお、GoogleのCLIENT_ID
とCLIENT_SECRET
の取得に関する情報を探すと、ライブラリ
画面からGoogle+API
を利用しているものがありますが、Google+APIはすでにサービスの提供が終了しており
2020年1月現在だと、ユーザー名やメールアドレスを取得するにあたりは、APIの追加が不要になっていることを確認しています。
omniauth の実装
Gemfile に下記を追加します。
gem 'omniauth'
gem 'omniauth-google-oauth2'
gem 'dotenv-rails'
$ bundle install
設定ファイルを編集する
config/initializers/devise.rb
に下記を追加する。
config.omniauth :google_oauth2, ENV['CLIENT_ID'], ENV['CLIENT_SECRET']
.env
ファイルを作成し、先程取得したクライアントIDとクライアントシークレットを入力します。
=
のあとは、クォーテーション''
不要です。
CLIENT_ID=クライアントID
CLIENT_SECRET=クライアントシークレット
コントローラーを追加する
devise を用いた users コントローラーを追加します。
$ rails g devise:controllers users
Running via Spring preloader in process 90155
create app/controllers/users/confirmations_controller.rb
create app/controllers/users/passwords_controller.rb
create app/controllers/users/registrations_controller.rb
create app/controllers/users/sessions_controller.rb
create app/controllers/users/unlocks_controller.rb
create app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================
Some setup you must do manually if you haven't yet:
Ensure you have overridden routes for generated controllers in your routes.rb.
For example:
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions'
}
end
===============================================================================
Users テーブルにカラムを追加する
マイグレーションファイルを作成し、カラムを追加します。
$ rails g migration add_columns_to_users provider uid username
class AddColumnsToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :provider, :string
add_column :users, :uid, :string
add_column :users, :username, :string
end
end
ここで追加したカラムを簡単に説明します。
- uid ユーザーID
- provider サービス名称
- name ユーザーの名前
$ rails db:migrate
ちなみに、email
などのカラムはすでにdevise 標準のため用意されています。マイグレーション実行後のdb/schema.rb
を見てみましょう。
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.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "provider"
t.string "uid"
t.string "username"
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
コントローラーを追加する
コントローラーを追加します。
Devise::OmniauthCallbacksController
を継承しているので、見慣れないメソッド名があるかと思いますが、provider
であるgoogle_oauth2
のメソッドが必要になります。
余談ですが、もし追加でprovider
を追加したときは、新たなメソッドとして、twitter
を定義し、同じくcallback
メソッドを呼び出せると、メソッドの中身を共通化できますね。
request.env['omniauth.auth']
に情報が格納されているため、この値を引数として既存のユーザーを探し出すか、新規作成します。この際、フラッシュメッセージは、Successfully authenticated from Google_oauth2 account.
と表示されます。
また、ユーザー情報がデータベースに保存されているかどうかで、リダイレクト先を変更します。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# You should configure your model like this:
# devise :omniauthable, omniauth_providers: [:twitter]
def google_oauth2
callback_from(:google_oauth2)
end
def callback_from(provider)
provider = provider.to_s
@user = User.find_or_create_for_oauth(request.env['omniauth.auth'])
if @user.persisted?
flash[:notice] = I18n.t('devise.omniauth_callbacks.success', kind: provider.capitalize)
sign_in_and_redirect @user
else
session["devise.#{provider}_data"] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
end
end
Userモデルにメソッドを追加する
request.env['omniauth']
のemail
からユーザー情報を取得し、新規ならば新たにレコードを作成します。
パスワードは、devise の特異メソッドであるfriendly_token
メソッドを使いランダムに生成します。
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:omniauthable, omniauth_providers: [:google_oauth2]
def self.find_or_create_for_oauth(auth)
find_or_create_by!(email: auth.info.email) do |user|
user.provider = auth.provider,
user.uid = auth.uid,
user.username = auth.info.name,
user.email = auth.info.email,
user.password = Devise.friendly_token[0, 20]
end
end
end
ルーティングを追加する
config/routes.rb
で、Users::OmniauthCallbacksController
へのルーティングを追加します。
Rails.application.routes.draw do
get 'top/index'
devise_for :users, controllers: {
omniauth_callbacks: 'users/omniauth_callbacks'
}
root to: 'top#index'
end
動作確認
Sign in with GoogleOauth2
のリンクが自動で生成されています。
これは、app/views/devise/shared/_links.html.erb
に自動でリンクが追加されているためです。便利ですね。
エラーの対処
外部通信を伴うエラー処理は切り分けが難しいですよね。いくつか対処した記録を残します。
Error: redirect_uri_mismatch
redirect_uri_mismatch
と出力されています。
リダイレクト先のURLを間違ってしまった場合は、下記の画面になります。
JWT::InvalidIatError
JWT::InvalidIatError
と出力されたら、OSのクロックがずれているエラーです。
config/initializers/devise.rb
ファイルを見直し、skip_jwt: true
を追記しましょう。
Devise.setup do |config|
`config.omniauth :google_oauth2, ENV['CLIENT_ID'], ENV['CLIENT_SECRET'], skip_jwt: true` skip_jwt: true # skip_jwt: true を追記
end
The action 'google_oauth2' could not be found for Devise::OmniauthCallbacksController
Devise::OmniauthCallbacksController
に対応するgoogle_oauth2
というアクションはないと言われています。
今回作成したのは、Devise::OmniauthCallbacksController
を継承したUsersコントローラーなので、config/routes.rb
があっているか確認しましょう。
3. Omniauth のテストコードを実装する
Omniauthを使った認証機能のテストを追加していきます。
本項は、下記の記事を参考にしました。
Gemを追加する
Gemfile
にrspec-rails
を追加します。
group :test do
gem 'rspec-rails'
end
$ bundle install
$ bundle exec rails generate rspec:install
Running via Spring preloader in process 4995
create .rspec
create spec
create spec/spec_helper.rb
create spec/rails_helper.rb
設定を追加する
spec/rails_helper.rb
にsupport
配下のRubyファイルを読み込む設定を追加します。
```Ruby:spec/rails_helper.rb`
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
### モックを追加する
`spec/support/omniauth.rb`を作成し、下記のコードを記載します。
```ruby:spec/support/omniauth.rb
OmniAuth.config.test_mode = true
OmniAuth.config.mock_auth[:google_oauth2] = OmniAuth::AuthHash.new({
provider: 'google_oauth2',
uid: '000000',
info: { email: 'test@example.com' },
credentials: { token:'google_oauth2_test' }
})
このコードをざっくり説明すると、下記のようになります。
- OmniAuth をテストモードを有効にしている。この設定を追加することで、すべてのOmniauthへのリクエストは、モックのAuth情報を用いて簡素化できるようになる
-
google_oauth2
のOmniAuthのモックとして疑似のAuth情報のハッシュを作成している
テストコードを実装する
spec/system/user.rb
を作成し、テストケースを追加します。
今回は、未サインアップの場合
とサインアップ済みの場合
をテストします。
require 'rails_helper'
RSpec.describe 'User', type: :system do
context '未サインアップの場合' do
it 'ユーザーが増えること' do
visit root_path
expect{
click_link 'Sign in with GoogleOauth2'
sleep 1
}.to change(User, :count).by(1)
end
end
context 'サインアップ済みの場合' do
before do
User.create!(
email: 'test@example.com',
password: 'test12'
)
end
it 'ユーザーは増えないこと' do
visit root_path
expect{
click_link 'Sign in with GoogleOauth2'
sleep 1
}.to_not change(User, :count)
end
end
end
まとめ
Railsアプリケーションに認証機能追加に関して、知見が深まりました。
拙い点がありましたがご指摘よろしくお願いします。