【Rails5】deviseとomniauthを使ったTwitter認証

色々な記事を参考にしたけど、結局色々な記事を見る羽目になったので個人的にまとめておきます。

環境変数等はガン無視でとりあえず実装します。

Twitterのデベロッパ申請は通っててAPIキーとAPIシークレットキーは持ってるものとします。

1. gemを入れる

Gemfileに以下のGemを入れて bundle install する。

gem 'devise'
gem 'omniauth'
gem 'omniauth-twitter'

2. まずはdeviseでログインを実装

とりあえずコマンドラインにこれを打つ

$rails g devise:install

次に devise と紐ついた User モデルを作成しマイグレート

$rails g devise user
$rake db:migrate

最後にサーバーを立ち上げて ~/users/sign_in にアクセスするとログイン画面ができてるはずです。

3. OmniAuthでTwitterの認証を実装

先ほどのUserモデルにカラムを追加します。ユーザーid(uid)はUserの確認に用います。

$rails g migration AddColumnsToUsers uid:string provider:string
$rake db:migrate

ここで引っ張ってこれるあたいは他にも色々あるのでomniauth-twitterのReadme参照
https://github.com/arunagw/omniauth-twitter


config/initializer/devise.rb の中に下記の3行目を追加します。
API Key, API secret, 〇〇 は適当なものを当てはめてください。

Devise.setup do |config| 
# ...
config.omniauth :twitter, 'API key', 'API secret', callback_url: "https://〇〇/users/auth/twitter/callback"
end

ローカルならコールバックは http://127.0.0.1:3000/users/auth/twitter/callback にしておけばいいかな


deviseメソッドに認証用のメソッドを追加し、userモデルも編集します。
app/model/user.rb を以下のように編集

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
          :recoverable, :rememberable, :validatable, :trackable, :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],
      )
    end
  # user.skip_confirmation!
    user
  end

  private

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

emailにはダミーを入れます。user.skip_confitmation!は確認用メールの送信を防ぎますが正直今はどっちでもいいのでコメントにしてます。


app/controllers/users/omniauth_callbacks_controller.rbに以下のコードを追加
(usersフォルダと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?
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

ビューを作成します。

$ rails g controller home index

app/home/index.html.erb を以下のように編集します。

<ul>
  <%if user_signed_in? %>
  <li><%=current_user.email%></li>
  <li><%=current_user.name.uid%></li>
  
  <li><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></li>
  <%else%>
  <li><%= link_to "ログイン", user_twitter_omniauth_authorize_path %></li>
  <%end%>
</ul>

最後にルーティングの設定です。

Rails.application.routes.draw do
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' } 
root to: 'home#index'
get 'home/index'

end

4. 完成

rails s でサーバーを立ち上げたらホーム(127.0.0.1)にあるログインボタンを押して、ログインできた後に画面にユーザーIDやダミーのメアドが出て入れば完成です。

あとがき

Qiitaの記事、あれ更新日時が検索結果に反映されるせいで、記事内に「現在は古いですのでこちらを参考に」みたいなザコい更新でも新規記事として上にくるんですよね。

基本的に多分コーディング関連の記事は新しいものを中心にリサーチすると思うので、個人のブログでも変に更新日を反映させないでほしいところです。