こんにちは。
GMOアドマーケティングのR.Sです。
今回は、前回のブログ「新しいRailsプロジェクトを作成してdeviseを実装する」のメールアドレスでのログイン機能に引き続き、「omniauth-twitter」を利用したTwitterログイン機能をプラスする手順を紹介します。
前回の続きとして扱うので、deviseによる認証が既に実装されている前提で進めていきます。
動作環境
- Rails 5.2.2
- devise 4.5.0
- oauth 0.5.4
- omniauth 1.8.1
- omniauth-oauth 1.1.0
- omniauth-twitter 1.4.0
Gemのインストール
Gemfileに利用するgemを記載します。
1 2 3 4 5 |
source 'https://rubygems.org' gem 'devise' #前回インストール済 gem 'omniauth' gem 'omniauth-twitter' |
$ bundle install
を実行してgemをインストールします。
Userモデルに必要なカラムを追加
Userモデルにツイッターログイン用のカラムを追加します。
追加するのは
- ツイッターログインということを保存する provider
- ユーザー毎に異なる uid
- ツイッターのIDを保存する username
の3つです。自由に変更しても大丈夫です。
$ bundle exec rails g migration AddColumnsToUsers provider:string uid:string username:string
と、実行してマイグレーションファイルを生成します。
作成されたマイグレーションファイルを編集して、uidとproviderの組み合わせでユーザーが一意に定まるようにUNIQUEインデックスを設定します。
1 2 3 4 5 6 7 8 |
class AddColumnsToUsers < ActiveRecord::Migration[5.2] def change add_column :users, :provider, :string add_column :users, :uid, :string add_column :users, :username, :string end add_index :users, [:provider, :uid], unique: true #これを追記する end |
編集したらマイグレーションを実行します。
$ bundle exec rake db:migrate
これでカラムが追加され、モデルの準備が整いました。
Twitter Application Managementの準備
次はTwitter側の準備です。アカウントにログインして、Twitter Application Managementでアプリケーションを作成します。
(新しくアプリケーションを作成するには、デベロッパーアカウントの申請が必要です。)
作成できたら、「Details」からアプリケーションの設定をします。
右上の「Edit」を押して、項目に従って設定してください。(Required)と書いてある項目は必須となっていますが、後から変更可能なので深く考えなくても大丈夫です。
- ポイント1
Allow this application to be used to sign in with Twitter という項目の「Enable Sign in with Twitter」にチェックを入れてログインを許可する
- ポイント2
CallbackURLは以下の2つを設定する
http://localhost:3000/users/auth/twitter/callback
http://localhost:3000/users/omniauth_callbacks
上段は $ bundle exec rake routes
コマンドで user_twitter_omniouth_callbacks のルーティングを確認したものです。
下段は後ほどつくるコールバック用コントローラーのURLです。
両方とも、usersの部分はルーティングに合わせて変更してください。
設定が完了したらSaveボタンを押して、設定完了です。
APIキーの準備
Twitter Application ManagementのKeys and Tokensタブでは、APIキーを確認できます。
キーを確認したら、config/initializers/devise.rb を編集してキーを追記します。
シークレットキーはGitHubなどに公開しないように注意が必要です。
また、開発環境と本番環境を分ける場合は、dotenvというgemを使ってファイルを分けるのが良いと思います。
1 2 3 4 5 6 |
Devise.setup do |config| config.omniauth :twitter, "API key", "API secret key", callback_url: "Twitter Application Managementで設定したCallback URLの下段のURL" #省略 end |
(たくさんの説明がコメントアウトしてあるので、それを翻訳するとなんとなくdeviseのことがわかった気持ちになれます。)
Userモデルの編集
モジュールを追加
omniauth用のモジュール「omniauthable」を追加します。
findメソッドを追加
uidとproviderはUNIQUEインデックスを設定したため、組み合わせは一意です。
それを利用してログインしようとしているユーザーを取得します。探した組み合わせが存在しない場合はレコードを作成します。
ダミーのメールアドレスを用意
deviseでのログインにはメールアドレスが必須なので、ツイッターでのログインもメールアドレスを保存する必要があります。
ダミーのアドレスを用意して、それを保存します。
編集後は以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :omniauthable #モジュールを追加 # findメソッドを追加 def self.find_for_oauth(auth) user = User.where(uid: auth.uid, provider: auth.provider).first unless user user = User.create( provider: auth.provider, uid: auth.uid, username: auth.info.nickname, 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 |
findメソッド内のauth.info.nickname
はauth["info"]["nickname"]
としても大丈夫です。
Userコントローラにコールバック処理を実装する
まずは以下を実行します。
$ bundle exec rails g controller omniauth_callbacks
作成されたomniauth_callbacks_controller.rb というファイルを下記のように編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class 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? 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 |
編集する前はApplicationControllerを継承していますがOmniauthCallbacksControllerを継承するように変更することに注意です。
omniauth.authという変数に入っている情報を元にユーザーが登録されているか判別して、登録されていたらログインする、登録されていない場合は登録ページに遷移するようにします。
ルーティングの設定
deviseを実装したときに設定されていたルーティングを、先ほど設定したOAuthのコールバック用のルーティングに変更します。
1 2 3 4 5 6 7 |
Rails.application.routes.draw do get 'welcome/index' devise_for :users, controllers: { omniauth_callbacks: 'omniauth_callbacks' } # ここを変更 # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html root 'welcome#index' end |
これでツイッターログインの準備が整いました!
サーバーを起動して、localhostに接続、
ログイン画面に遷移後、「Sign in with twitter」を押すとログイン出来ます!
これでツイッターログインの実装の紹介は終わりです。
deviseのときと同様、割と簡単にログイン機能が実装できるし、とても自由度が高いところが良いと思いました。
ツイッターIDだけでなくプロフィール画像や説明欄の内容なども簡単に取得できます。
詳しくはomniauth-twitterのAuthentication Hashのところに書いてあるので見てみてください。
(しかし、gemの相性もあるのか、ハマったポイントもあったので以下に書いておきます。)
ハマりポイント
前回と今回のブログでは、deviseを実装後、omniauth-twitterを実装という順番で紹介しました。
逆の順番で実装しようとしていた時にハマりポイントがあったので紹介します。
user_signed_in? などのヘルパーメソッドが常にfalseを返す
アプリケーションコントローラを確認してください。
deviseの実装前にログイン機能を実装していると、current_userというメソッドを自身で用意していることが多いと思います。その場合、deviseの実装時に用意されたcurrent_userが機能しないため、current_userを利用したメソッドが常にfalseを返すようになります。
自身で用意した方のメソッド名を変えるか、削除することで解決できます!
invalid_credentialsというエラーが出る
config/initializers/omniauth.rb の中身はいじらない。
deviseを使わずにomniauth-twitterを実装するときは書き込むことがありますが、deviseではそれを推奨していません。
deviseの公式ドキュメントのWiki、OmniAuth:Overviewの部分に記載があります。
以上、ハマりポイントでした。公式ドキュメント読むのが最も大切だと感じました。