52
61

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Railsアプリに簡単なTwitterログインを実装する

Last updated at Posted at 2019-12-31

簡単なTwitterログインを実装したので、方法をまとめていきます。
ログイン方法はTwitter連携だけなので、devise等は利用していません。

仕様は以下の通りです。

  • ログイン方法はTwitterのみ(メールアドレスでのログインは出来ない)
  • ログインボタンをクリックすると、Twitterの認証画面に遷移する
  • 初めてログインする場合にはusersテーブルにレコードを作成、2回目以降の場合には既存のデータを読み込む
  • ログイン後は、sessionが開始する

アプリはすでにあって、トップページ等の設定は出来ている前提で話を進めていきます。

##API Key、API Secret Keyを取得
Twitterと連携するためには、TwitterのAPIキーとAPIシークレットキーが必要です。以下の手順で取得しましょう。

###アカウント取得
まずは以下の記事等を参考に、開発者アカウントを取得しましょう。
Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ ※2019年8月時点の情報
2019年12月29日に申請を出したところ、即時承認されました。待ち時間0秒でした。

###アプリ作成
アカウント取得、ログイン後
https://developer.twitter.com/en/apps/create
よりアプリを作成します。

Callback URLsには
http:localhost:3000/auth/twitter/callback
http:0.0.0.0:3000/auth/twitter/callback
http:<本番環境のドメイン>/auth/twitter/callback
https:<本番環境のドメイン>/auth/twitter/callback
の4つを指定します。
最低2つ設定されていないと動かない仕様になっているようです。

他は基本的にはそれっぽいことを書いておけばOKです。
また設定は後から自由に変更できます。

###キーを取得
アプリ一覧画面
https://developer.twitter.com/en/apps
から作成したアプリ右の「Details」ボタンをクリック→「Keys and tokens」タブからAPIキーとAPIシークレットキーが取得出来ます。

##必要なgemのセットアップ
gemのインストールと、各種設定を行います。

###dotenv-rails
APIキーとAPIシークレットキーを環境変数に保存するためにdotenv-railsを導入します。

Gemfile
gem 'dotenv-rails'
$ bundle install

プロジェクトルートに.envファイルを作成し、上記で取得した各種キーを書き込みます。

.env
TWITTER_API_KEY = hogehoge
TWITTER_API_SECRET = foobarbaz

###omniauth-twitter
Twitter連携のためのgemomniauth-twitterを導入します。

Gemfile
gem 'omniauth-twitter'
$ bundle install

config/initializers/omniauth.rbを作成し、APIキーとAPIシークレットキーを書き込みます。

config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, ENV['TWITTER_API_KEY'], ENV['TWITTER_API_SECRET']
end

##モデル、データベースを作成
TwitterのID、ニックネーム、ユーザー名、画像パスを保存するためのデータベースと関連するモデルを作成します。
上記は全てomniauth-twitterで取得できる値です。その他の値についてはomniauth-twitterのREADMEをご覧ください。

$ rails g model User uid:string nickname:string name:string image:string
$ rails db:migrate

##セッション管理用のヘルパーメソッドを作成

app/helpers/sessions_helper.rb
module SessionsHelper
  # 渡されたユーザーでログインする
  def log_in(user)
    session[:uid] = user.uid
  end

  # 現在ログイン中のユーザーを返す (いる場合)
  def current_user
    if session[:uid]
      @current_user ||= User.find_by(uid: session[:uid])
    end
  end

  # ユーザーがログインしていればtrue、その他ならfalseを返す
  def logged_in?
    !current_user.nil?
  end

  # 現在のユーザーをログアウトする
  def log_out
    session.delete(:uid)
    @current_user = nil
  end
end

##ログイン、ログアウト処理を実装

$ rails g controller Sessions
app/controllers/sessions_controllers.rb
class SessionsController < ApplicationController
  def create
    unless request.env['omniauth.auth'][:uid]
      flash[:danger] = '連携に失敗しました'
      redirect_to root_url
    end
    user_data = request.env['omniauth.auth']
    user = User.find_by(uid: user_data[:uid])
    if user
      log_in user
      flash[:success] = 'ログインしました'
      redirect_to root_url
    else
      new_user = User.new(
        uid: user_data[:uid],
        nickname: user_data[:info][:nickname],
        name: user_data[:info][:name],
        image: user_data[:info][:image],
      )
      if new_user.save
        log_in new_user
        flash[:success] = 'ユーザー登録成功'
      else
        flash[:danger] = '予期せぬエラーが発生しました'
      end
      redirect_to root_url
    end
  end


  def destroy
    log_out if logged_in?
    flash[:success] = 'ログアウトしました'
    redirect_to root_url
  end
end

##ログイン、ログアウト用のリンクを追加

app/views/layouts/_header.html.erb
<header class="header">
.
.
  <% if logged_in? %>
    <%= link_to 'ログアウト', logout_path %>
  <% else %>
    <a href="/auth/twitter">ログイン</a>
  <% end %>
.
.
</header>

##ルーティングを設定

config/routes.rb
Rails.application.routes.draw do
.
.
  get '/auth/:provider/callback', to: 'sessions#create'
  get '/logout', to: 'sessions#destroy'
end

omniauth-twitterの仕様で、/auth/twitter/callback/auth/:provider/callbackに変換されます。

ログイン状態の振る舞いのテスト

今回、session[:uid]にユーザーidを代入形でログイン処理を実装しました。
RSpecでログイン状態のユーザーを作る時にもsession[:uid] = user.uidと書きたいところですが、
RSpecのfeature spec及びsystem specではデフォルトでsessionメソッドが使えません。
そこでrack_session_accessをインストールして使えるようにします。

Gemfile
group :test do
# 省略
  gem 'rack_session_access'
end
$ bundle install
config/environments/test.rb
Rails.application.configure do
# 省略
  config.middleware.use RackSessionAccess::Middleware
spec/spec_helper.rb
RSpec.configure do |config|
# 省略
  require 'rack_session_access/capybara'
end
spec/systems/sample_spec.rb
it 'ログイン' do
  visit root_path
  expect(page).to_not have_content 'マイページ' # ログイン前はマイページという表示が無い
  page.set_rack_session(uid: user.uid) # ログイン
  visit root_path
  expect(page).to have_content 'マイページ' # マイページと表示されている
end

##参考

52
61
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
52
61

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?