[Rails]DeviseとOmniauthでソーシャルログイン機能を実装！

# はじめに
今時のアプリで、ソーシャルログイン機能が搭載されていないものは少ないです。そう言った意味でも必須の機能になりつつあるかと思うので、実装できるようにしましょう！

# 実装手順
1.必要なgemを導入して、 `bunde install`を実行する。

```ruby
# Gemfile
gem 'devise' #ユーザー認証
gem 'devise-i18n' #deviseの日本語化
gem 'omniauth-twitter' #twitter認証
gem 'omniauth-facebook' #facebook認証
gem 'omniauth-google-oauth2' # google認証
gem 'omiauth-github' # github認証
gem 'dotenv-rails' #環境変数の設定
```

2.deviceのセットアップを行う。

```bash
$ rails g devise:install

$ rails g devise:views
```

3.Userモデルを生成し、マイグレーションファイルを修正する。また、生成したモデルファイルを以下のように修正する。

```bash
$ rails g devise user
```

```app/models/user.rb
devise :database_authenticatable, :registerable,
       :recoverable, :rememberable, :trackable, :validatable, :omniauthable
```

4.OmniAuthでは`uid`（一意のID）と`provider`（FacebookやTwitterなど）をカラムを追加し、マイグレーションを実行する。

```bash
$ rails g migration AddColumnsToUsers uid:string provider:string

$ rails db:migrate
```

5.各プラットフォームの設定を行う。

【Twitterの場合】
[こちら](https://developer.twitter.com/en/apps)からアプリケーションを作成してください。
その後、Settingより以下の設定を行う。

```ruby
# Callback URL
https://localhost:3000/users/auth/twitter/callback

# 以下にチェックを入れる：
[Allow this application to be used to Sign in with Twitter]
```

【Facebookの場合】
[こちら](https://developers.facebook.com/)からログイン後、アプリケーションを作成する。
APPIDとSECRETはアプリ一覧ページから対象のアプリを選択し、Settings⇨Basicsから確認できます。

※[Valid OAuth Redirect URIs]に、以下のコールバックURLをセットする。

```
https://localhost:3000/users/auth/facebook/callback
```

【Goodleの場合】
[こちら](https://console.cloud.google.com)からプロジェクトを作成する。API認証の設定からOauthクライアントIDを作成します。
その後、以下のコールバックURLをセットする。

```
http://localhost:3000/users/auth/google_oauth2/callback
```

【Githubの場合】
[こちら](https://github.com/settings/apps)からアプリを作成する。その後、以下を入力する。

```ruby
# アプリ名
sample_app

# ホームページのURL
http://localhost:3000/

# コールバックURL
http://localhost:3000/users/auth/github/callback
```

6.先ほど手に入れたIDとSECRETを`.env`に記載する。その後、.envファイルが公開されないようにします。

```.env
TWITTER_API_KEY="取得したTwitterAPIキー"
TWITTER_SECRET_KEY="取得したTwitterシークレットキー"
FACEBOOK_KEY='取得したFacebookのAppID'
FACEBOOK_SECRET='取得したFacebookのAppSecret'
GOOGLE_CLIENT_ID='取得したGoogleのクライアントID'
GOOGLE_CLIENT_SECRET='取得したGoogleのクライアントシークレット'
GITHUB_ID='取得したGithubのクライアントID'
GITHUB_SECRET='取得したGithubのシークレット'
```

```.gitignore
...
.env
...
```

7.環境変数を読み込む設定を行う。

```initializers/devise.rb
Devise.setup do |config|
  ...
  config.omniauth :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']
  config.omniauth :twitter, ENV['TWITTER_API_KEY'], ENV['TWITTER_API_SECRET']
  config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET']
  config.omniauth :github, ENV['GITHUB_ID'], ENV['GITHUB_SECRET']
  OmniAuth.config.logger = Rails.logger if Rails.env.development?
end
```

8.ユーザーを探索するクラスメソッドを実装する。

```app/models/user.rb
class User < ActiveRecord::Base
  # ...

  def self.find_for_oauth(auth)
    user = User.where(uid: auth.uid, provider: auth.provider).first

    unless user
      user = User.create(
        uid:      auth.uid,
        provider: auth.provider,
        email:    User.dummy_email(auth),
        password: Devise.friendly_token[0, 20]
      )
    end

    user
  end

  private

  # 今はダミーのメールアドレスを入力しているが任意で変更する
  def self.dummy_email(auth)
    "#{auth.uid}-#{auth.provider}@example.com"
  end
end
```

9.コールバック処理を実装する。

```class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
class User < Devise::OmniauthCallbacksController
  def facebook
    callback_from :facebook
  end

  def twitter
    callback_from :twitter
  end

  def google_oauth2
    callback_from :google_oauth2
  end

  def github
    callback_from :github
  end

  private

  def callback_from(provider)
    provider = provider.to_s

    @user = User.find_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, event: :authentication
    else
      session["devise.#{provider}_data"] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end
end
```

10.ルーティングを設定する。

```config/routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

  # ...
end
```

11.ビューに以下のリンクを追加する。

```ruby
<%= link_to('Twitterでログインする', user_omniauth_authorize_path(:twitter)) %>
<%= link_to('Facebookでログインする', user_omniauth_authorize_path(:facebook)) %>
<%= link_to('GooGleでログインする', user_omniauth_authorize_path(:google_oauth2)) %>
<%= link_to('Githubでログインする', user_omniauth_authorize_path(:github)) %>
```


# 終わりに
ユーザーが利用しやすいアプリを実装するために、こういったログイン方法を用意しておくと楽なので喜ばれます。そこまで難しい実装でも無いので、積極的に導入してみましょう！

# 参考
[RailsにDevise+OmniAuthでユーザ認証を実装する手順]
(https://qiita.com/zenizh/items/94aec2d94a2b4e9a1d0b)

[【Rails】DeviseとOmniauthを使ってGoogle、Twitter、Facebook認証]
(https://qiita.com/d0ne1s/items/e1ee23ea23343d6aaa34)

[RailsにDevise+OmniAuthでユーザ認証したい]
(https://qiita.com/zizynonno/items/7eabb61cb1c3fcbc258a)

[RailsでFacebookとGoogleのOAuth連携。SNS認証の方法]
(https://qiita.com/nakanishi03/items/2dfe8b8431a044a01bc6)

[【Rails6】Devise + OmniAuthでGitHub認証を実装する【初学者向けチュートリアル】]
(https://qiita.com/lamp7800/items/84ac4f9f7f5d4e171f1d)

[device-i18n]
(https://raw.githubusercontent.com/tigrish/devise-i18n/master/rails/locales/ja.yml)