【Rails】deviseとomniauth-twitterでTwitterアカウントを使った認証処理 

#環境
ruby 2.6.7
Rails 5.2.6

#手順

##TwitterAPIの設定

TwitterAPI登録作業については、こちらを参考に行いました
https://pocco.net/twitter-developer/

Twitter社の審査があって、取得に時間がかかるので注意です。

登録が出来たらDeveloper Portalのページで設定します
https://developer.twitter.com/en/portal/dashboard
登録の際に表示されるAPIキーは後で使います。

アプリの作成から
Settings　→ Authentication settingsと進んで
Callback URLsを設定します。

```
http://127.0.0.1/users/auth/twitter/callback
http://localhost:3000/users/auth/twitter/callback
http://（本番環境のURL）/users/auth/twitter/callback
```

![スクリーンショット 2021-08-16 6.18.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896190/8c73da79-d693-f07d-30f5-d34df9d61e25.png)


##Railsへの実装


主にこの記事を参考にさせてもらいましたが、今ではインストールするgemが違っていたりするので、以下が今のやり方となります。

Gemfileに以下を追記します



```Gemfile
gem 'omniauth-rails_csrf_protection'
gem 'omniauth-twitter'
gem 'devise'
gem 'dotenv-rails'
```

インストールします

```
$ bundle install
```

deviseをインストールします

```
$ rails g devise:install
```

実行するとこういうのが出てきて一見エラーに見えますが、
これでdeviseのインストールは成功しています

```
===============================================================================

Depending on your application's configuration some manual setup may be required:

  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.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"
     
     * Not required for API-only Applications *

  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>

     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views
       
     * Not required *

===============================================================================
```

ユーザーのテーブルを作成します

```
$ rails g devise user
```

Twitterアカウント情報用のカラムがないので、追加（name, uid, provider）

```db/migrate/日時_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  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.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.string :name #追記
      t.string :uid #追記
      t.string :provider #追記

      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

```

マイグレーション

```
$ rake db:migrate
```

コントロールを作成します

```
$ rails g devise:controllers users
```

##APIキーの設定

.envを作成し、2種類のAPIキーを貼り付けます

```.env
TWITTER_ID='ペースト'
TWITTER_APP_SECRET='ペースト'
```

.envがgitに上がるとまずいので、.gitignoreに以下を追記

```.gitignore
/.env
```


```config/initializers/devise.rb
Devise.setup do |config|

(省略)

config.omniauth :twitter, ENV['TWITTER_ID'], ENV['TWITTER_APP_SECRET'] #追記

（省略）

end
```

##user.rb編集

```app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable

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

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

  private

  def self.dumy_email(auth)
    "#{auth.uid}-#{auth.provider}@example.com"
  end
end
```

メールアドレスはダミーの値が設定されるようになっています

##route.rb編集

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

##omniauth_callbacks_controller.rb編集

```app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def twitter
    callback_from :twitter
  end

  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
      session[:user_id] = @user.id #追記
    else
      session['devise.#{provider}_data'] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end
end
```

以下のリンクでTwitterログイン処理ができます

```
<%= link_to 'Twitterログイン', user_twitter_omniauth_authorize_path ,method: :post %>
```