Twitter認証を使って二つのモデルでログインする際の注意(OmniAuth＋devise)



deviseを複数のモデルでのTwitter認証を実装しようとすると、うまくいかない。
自分は開発中のuserモデルとartistモデルがあるケースでつまったのでまとめていきます。

# twitterapiの設定

Twitterのdeveloperアカウントは2018年の秋頃からしようが変更になり、英語でサービスがどのように使われるかを明示しなければならなくなりました。
https://qiita.com/tdkn/items/521686c240b0c5bc6207
承認されない時は、twitter社からメールが届き、いくつかの質問がされます。自分は2回ほどのメールのやり取りを経て、やっとアカウントが承認されました。（サービスをもっと具体的に教えろなど...）


# APIKEYを設定してdeviseとomniauthの設定
```
gem 'devise'
gem 'omniauth-twitter'
```
を入れて、

下の記事のようにdeviseの設定とomniauthの設定をします
https://qiita.com/daigou26/items/d84e64af775a3054e950


# 複数モデルに適用させる

問題はここからです。omniauth+deviseだと複数モデルの時に適用されないのです。
実は公式のドキュメントに、

> 現時点では、DeviseのOmniauthableモジュールはそのままでは1つのモデルでしか利用できません。しかしご安心ください。
> OmniauthableはOmniAuthの単純なラッパーにすぎないので、方法はあります。

と、記載があります。
手順にそって、複数modelにおいてもsns認証ができるようにしていきましょう。

### 1. deviseにおいてomniauthを使わない。
まず、userとartistのcontrollerにある

```
devise :omniauthable
```
を削除します。

### 2.ルーティング作成
また、```routes.rb```に、

```
get "/auth/twitter/callback" => "omniauth_callbacks#twitter"
get '/auth/another/twitter/callback' => 'anothers#twitter'
```
と記述し、deviseを使わずにそれぞれのルーティングを作成します。

### 3. controller設定

~~次に```controllers/omniauth_callbacks.rb```というコントローラーを作成し、~~
次に```controllers/omniauth_callbacks__controller.rb```というコントローラーを作成し、

```
class OmniauthCallbacksController < ApplicationController
  def twitter
    callback_from :twitter
  end

  def failure
    @notice = "failure"
    redirect_to events_path, notice: 'failure'
  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")
      @notice = "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']
      @notice = "user is not persisted."
      redirect_to root_path, notice: 'user is not persisted.'
    end
  end
end
```
と記述します。
次に別の```anothers_controller.rb```というコントローラーを作成し、


```
class AnothersController < ApplicationController
  def twitter
    callback_from :twitter
  end

  def failure
    @notice = "failure"
    redirect_to events_path, notice: 'failure'
  end


  private

  def callback_from(provider)
    provider = provider.to_s

    @artist = Artist.find_for_oauth2(request.env['omniauth.auth'])

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

```
とし、別のモデルからの設定をします。

### 4.プロバイダ作成
二つのルーティングができるようにプロバイダを変更します。


```config/initializers/omniauth.rb

OmniAuth.config.full_host = "https://hogehoge.com" 
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'],info_fields:"nickname, image", request_path: '/auth/twitter', callback_path: '/auth/twitter/callback'
  provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'],info_fields:"nickname, image", request_path: '/auth/another/twitter', callback_path: '/auth/another/twitter/callback'
end
```

### 5.viewの設定
これで、

```
<%= link_to 'twitterでログイン', '/auth/twitter', :id => "twitter" %>
<%= link_to 'twitterでログイン', '/auth/another/twitter', :id => "twitter" %>
```

と記述すると、無事ルーティングされます。


# 参考記事
https://qiita.com/RyosukeKawamura/items/ff1116b0a1d861a24c62