概要
RailsのTwitterアカウントでの連携ログインについて、少しハマったのでメモしつつ、解決方法を提案できたらと思います。
TwitterAPIの仕様が数ヶ月前に変更されたあとの記事が少なく感じました(2018/10現在)。
また、deviseなるものとomniauth-twitterを連携させたものがあるようですが、今回はomniauth-twitter単体での実装です。また、作ったアプリケーションはHerokuにデプロイするところまで書きたいと思います。
開発環境
macOS High Sierra v10.13.6
ruby 2.5.1
rails 5.2.1
direnv
Heroku
準備
RailsやRubyの導入は省きます。
direnv
ディレクトリごとに環境変数を設定できるコマンドラインツールです。
導入
- macOS
Homebrewが入っているなら、コマンドひとつでインストールできます。
$ brew install direnv
- Windows・その他
リリースページからダウンロードしましょう。
https://github.com/direnv/direnv/releases
インストール後は忘れずに「.bashrc」に設定を書きます。
$ echo 'export EDITOR=vim' >> ~/.bashrc
$ echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
$ source ~/.bashrc
詳しい使い方は次のURLを参照してください。
https://www.softantenna.com/wp/review/direnv/
Heroku
言わずとしれたデプロイサイト。railsアプリをpushするだけでデプロイが終わっちゃう驚き。
ローカル環境でOK!って人は飛ばしてください。
Herokuを導入する以前にgitを導入する必要があるんですが、ここでは省略します。
Herokuは次のURLからダウンロードしてください。
https://devcenter.heroku.com/articles/heroku-cli
TwitterAPI
個人的にちょっと厄介なこいつ。2018年9月の仕様変更によってAPIの使用に審査が必要になって、使用目的とか取得したデータの扱いとかを300文字以上の英語で送ります。Google翻訳を駆使したりしてがんばります。
APIの審査についてのURLです。ちなみに私は審査を出した当日に承認されました(2018/10)。
https://qiita.com/tdkn/items/521686c240b0c5bc6207
【重要】TwitterAPIの設定なんですが、CallBack_URLを適切に指定しないとエラーでます。
これ、意外とハマるんじゃないかと思います。
omniauth-twitterのみの場合、callback_urlは
http://localhost:3000/auth/twitter/callback
とかですね。
deviseをかませる場合少し違った気がします。
どこぞのQiita記事でlocalhostはcallback_urlに指定できないとか書いてたのでそれは間違いだって言いたいです。
TwitterAPIのCallBackについて次の記事を参考にしました。
https://saruwakakun.com/memo/omniauth-twitter
ローカル導入
まずは、ローカルでの構築を行っていきます。
新規アプリ作成とGem導入
$ rails new twitter-auth
$ cd twitter-auth/
twitter-authというアプリ名で作成します。次にGemfileを編集します。
gem 'omniauth'
gem 'omniauth-twitter'
Gemfileを編集したので忘れずにbundle installをします。
$ bundle install
APIキーの登録
用意したTwitterAPIを環境変数に設定します。
$ direnv edit .
vimが開きます。
vimの詳しい使い方についてはコチラ。
とりあえず、「i」キーを押してINSERTモードに変更して
export TWITTER_KEY="your_twitter_api_key"
export TWITTER_SECRET="your_twitter_api_secret"
書き終えたら「Esc」キーでINSERTモードを抜けて、
「:wq」と入力します。するとターミナルに戻ります。
環境変数はGitとかで公開してはダメなので、「.gitignore」に追記します。
$ echo ./.envrc >> .gitignore
次に、設定した環境変数をomniauthに設定します。ファイルが無いので新規作成して次を記述します。
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter,
ENV["TWITTER_KEY"],
ENV["TWITTER_SECRET"]
end
Userモデル作成
まずはモデルを作成します。
$ rails g model user provider:string uid:string user_name:string image_url:string
次にモデルの定義です。引数のauthはTwitterAPIのレスポンスデータで、様々な情報が格納されている。
class User < ApplicationRecord
def self.find_or_create_from_auth(auth)
provider = auth[:provider]
uid = auth[:uid]
user_name = auth[:info][:name]
image_url = auth[:info][:image]
self.find_or_create_by(provider: provider, uid: uid) do |user|
user.user_name = user_name
user.image_url = image_url
end
end
end
この他にもデータを取得したい場合は次の一覧から適切な変数を指定することでデータを取得できる。
https://github.com/arunagw/omniauth-twitter#authentication-hash
ex) ログインした人のTwitterURLをtwitter_urlに格納する。
twitter_url = auth[:info][:urls][:Twitter]
Login/Registerコントローラ作成
ログイン、ログアウトに使うSessionコントローラを作成します。
$ rails g controller sessions
そして次を記述します。
class SessionsController < ApplicationController
def create
user = User.find_or_create_from_auth(request.env['omniauth.auth'])
session[:user_id] = user.uid
flash[:notice] = "ユーザ認証が完了しました。"
redirect_to root_path
end
def destroy
reset_session
flash[:notice] = "ログアウトしました。"
redirect_to root_path
end
end
ヘルパーメソッドの記述
current_user(ログイン中のユーザ情報)の取得やログイン中かどうかを返すヘルパーメソッドを定義します。
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
helper_method :current_user, :logged_in?, :authenticate
private
def current_user
return unless session[:user_id]
@current_user ||= User.find_by(uid: session[:user_id])
end
def logged_in?
!!session[:user_id]
end
def authenticate
return if logged_in?
redirect_to root_path, alert: "ログインしてください"
end
end
viewの設定
viewを定義します。今回は、pagesのindexをroot_pathとして、showをログインが必要なページとします。
rails g controller Pages index show
まずは、全体に適用するviewとして、
部分を下に変更してください。<body>
<header>
<% if logged_in? %>
<%= link_to 'Logout', '/signout' %>
<% else %>
<%= link_to 'Twitter Login', '/auth/twitter' %>
<% end %>
</header>
<% if flash[:notice] %>
<div class="notice">
<%= flash[:notice]%>
</div>
<% end %>
<%= yield %>
</body>
ぶっちゃけ、indexとshowは何も書かなくていいような気がするんですけど、一応わかりやすくするために書いてます。
<h1>TwitterAuthTest</h1>
<p>Find me in app/views/pages/index.html.erb</p>
<%= link_to 'User Page', '/pages/show' %>
<% if logged_in? %>
<h1>こんにちは、<%= current_user.user_name %>さん</h1>
<p>ユーザー用ページです。</p>
<% else %>
<p>ログインしてください</p>
<% end %>
routesの設定
routesの設定です。
Rails.application.routes.draw do
root 'pages#index'
get 'pages/show'
get '/auth/:provider/callback', to: 'sessions#create'
get '/signout', to: 'sessions#destroy'
end
ローカルで動かす
以上で導入は完了です。ローカルで動かすためにはマイグレーションをするのを忘れないでください。
$ rails db:migrate
$ rails s
起動画面
起動画面はこんな感じです。
Twitterでログインをしたら。
User Pageをクリック。
(一部隠してます)
Herokuにデプロイ
Herokuにデプロイしてみます。
データベースシステムの変更
まず、現在使用しているSQLite3はHerokuで使えない仕様なので、PostgreSQLを使うようにGemを変更します。
- 上の方にある「gem 'sqlite3'」は削除するか、先頭に#をつけてコメントアウトしましょう。
- 「group :development do」の中に「gem 'sqlite3'」を書きます。
- 「group :production do」を追記して中に「gem 'pg'」を書きます。(endを忘れずに書きます。)
これは、データベースシステムを開発環境ではSQLite3を使って本番環境 (Heroku)ではPostgreSQLを使いますという意味です。
.
.
# gem 'sqlite3'
group :development do
.
.
gem 'sqlite3'
end
group :production do
gem 'pg'
end
.
.
今後、ローカルで開発するときのためにオプションをつけてbundle installします。
$ bundle install --without production
Rails Tutorialでもおなじみのこれです。groupがproductionのものはローカルにインストールしないという意味です。
いざデプロイ
herokuにデプロイする準備ができたのでデプロイします。
$ heroku create [your_heroku_app_name]
$ git add .
$ git commit -am "init"
$ git push heroku master
$ heroku run rails db:migrate
$ heroku config:set TWITTER_KEY=your_twitter_api_key
$ heroku config:set TWITTER_SECRET=your_twitter_api_secret
TwitterAPIのページでCallBack_URLを設定します。これがないとエラー吐きます。
CallBackに以下のリンクを追加します。
https://[your_heroku_app_name].herokuapp.com/auth/twitter/callback
うまくデプロイできれば次のURLでアプリケーションが動いてるところを見ることができます。
https://[your_heroku_app_name].herokuapp.com/
ハマったポイント
ここから恥ずかしい話になります。
これを実装するのに3日ほどかかりました。なぜかというと、400エラーやら403エラーに襲われたからです・・・。
もしかしたら同じようなエラーで困っている人のために解決法を書いておきます。
400エラー
私の場合、TwitterのAPIキーがうまく設定できておらず、APIリクエストを投げる際にAPIキーを送れていなかったときに出ました。
direnv
の設定で.bashrc
にeval "$(direnv hook bash)"
を書き忘れていたおかげでrailsが.envrc
を読まないという原因でした。
403エラー
TwitterAPi設定で、CallBackURLを正しく指定していなかったときに発生しました。
ローカルで開発の場合は、
http://localhost:3000/auth/twitter/callback
http://127.0.0.1:3000/auth/twitter/callback
この2つを設定しておきましょう。
Herokuなどにデプロイした場合も、その都度callback_urlを設定するのを忘れないようにしましょう。
まとめ
Railsにomniauth-twitterを用いたTwitter連携ログイン機能について軽く説明を交えつつ実装方法を書きました。
Rails初心者が書いた&コピペなので間違ったコードや間違った説明などしている所あるかもしれません。
今回の開発をgithubに上げました。
https://github.com/white0221/twitter_auth_on_rails
最後まで読んでいただきありがとうございました。
開発の助けになれば幸いです。
参考
https://github.com/arunagw/omniauth-twitter
https://qiita.com/puremoru0315/items/f1d459b663fd3b715dee
https://qiita.com/ntkgcj/items/c3108c19fb64acc9dd8d