RailsでTwitterログイン認証を実装

RailsアプリでTwitterログインを実装する方法をまとめます。

##deviseの導入
メールアドレスやSNSアカウントを用いてのログインを、簡単に実装するGem「devise」と、OAuth認証に必要なGem「omniauth」「omniauth-twitter」を導入します。

```ruby:Gemfile.rb
gem 'devise'
gem 'omniauth'
gem 'omniauth-twitter'

#envファイルで環境変数を管理する用のgemです。合わせてインストールしておきましょう
gem 'dotenv-rails'
```
続いて、bundle installを行います。

```
bundle install
```
※ライブラリはサーバーの起動時に読み込まれるので、ここでいったんサーバーを停止し、再起動しましょう。

##deviseの設定

アプリケーションにdeviseをインストールします。

```
rails g devise:install
```
1から4までのステップが書かれた英文が表示されるので、指示通りにコーディングします。

###デフォルトURL

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }をconfig/environments/development.rbに追加します。

```ruby:config/environments/development.rb
Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

・・・(略:場所はどこでも良いです)

  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end
```

###root_urlを指定
ルートURLにアクセスした際のページを作成します。

```
rails g controller Pages index
```
Pagesコントローラーには、indexアクションと、ビューファイルindex.html.erbを追加しています。

###フラッシュメッセージを指定
ログインが成功した際に表示する、フラッシュメッセージを、application.html.erbの<body>下に指定します。

```ruby:app/views/layouts/application.html.erb
・・・(略)
</head>
<body>
  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>

    <%= yield %>
</body> 
```
###devise用のviewを作成
```
rails g devise:views
```
app/views/devise/以下にファイルが作成されます。

##Userモデルを作成
```
rails g devise user
```
※モデル名なので単数形

これにより、dbフォルダ下にマイグレーションファイルが作成されます。

##ユーザーモデルを編集
user.rbのdevise:以下に「:omniauthable」を追加します。

```ruby:model/user.rb
devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable
```

###データベースにカラムを追加
deviseはデフォルトでメールアドレスとパスワードした扱うことができません。ツイッターログインで扱うデータのカラムをあらかじめ追加しておく必要があります。

以下のカラムを追加します。

- ユーザーID（uid）
- プロバイダー（provider)
- アカウント名(name)
- アカウントID(nickname)
- 場所(location)
- 画像(image)

```
rails g migration AddColumnsToUsers uid:string provider:string name:string nickname:string location:string image:string
```

ここまで終わったら、以下マイグレーションを実行します。

```
rails db:migrate
```

##Twitter Developerの登録
API Keyと、Secret Keyを取得します。(省略)

###取得した2つのキーを貼り付け

```ruby:config/initializer/devise.rb

Devise.setup do |config|
・・・(略)
　　config.omniauth :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end
```
APIキー自体はenvファイルに記入します。

```/.env
TWITTER_KEY="XXXXXXXXX"
TWITTER_SECRET="XXXXXXXXXXXXXXX"

```

.gitignoreファイルに以下を追加します。

```/.gitignoreignore
/.env
```

###Userモデルを編集する

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


    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],
        image: auth.info.image,
        name: auth.info.name,
        nickname: auth.info.nickname,
        location: auth.info.location
      )
    end

    user
  end

  private

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

end

```
Teitter認証の際に取得した各データを、データベースに格納しています。メールアドレスがない場合はdevise側でエラーが発生してしまうので、ダミーのアドレスを作成しています。

###コールバックの設定
app/controllers/以下に「users」フォルダを作成し、その下に「omniauth_callbacks_controller.rb」ファイルを作成します。

omniauth_callbacks_controller.rbは以下のように編集します。

```omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def twitter
    callback_from :twitter
  end

  private
  def callback_from(provider)
    provider = provider.to_s

    @user = User.find_for_oauth(request.env['omniauth.auth'])

    if @user.persisted?
      print("persisted true")
      flash[:notice] = I18n.t('devise.omniauth_callbacks.success', kind: provider.capitalize)
      sign_in_and_redirect @user, event: :authentication
    else
      print("persisted false")
      session["devise.#{provider}_data"] = request.env['omniauth.auth']
      redirect_to controller: 'sessions', action: 'new'
    end
  end
end
```

###ルーティングの設定
config/route.rbのdevise_forを、以下のように編集します。

```config/route.rb
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
```

###ビューファイルを整える
ビューファイルを以下のように整えます。

```ruby:index.html.rb
<%if user_signed_in? %>
<%=current_user.email%>

<%=current_user.name%>
<%=current_user.nickname%>
<%=current_user.image%>
<%=current_user.location%>
  
  <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
  <%else%>
  <%= link_to "ログイン", new_user_session_path %>
<%end%>
```

以上でツイッター認証ログインが可能になりました。