RailsでTwitterログインしてつぶやいてみる

タイトルのことをやってみたくて調べたり作ったりしたので書きます

ログイン編

導入

omniauth-twitter というgemを使いました

omniauthとはなんぞやというと

OmniAuth is a library that standardizes multi-provider authentication for web applications.

webアプリケーションで様々なプロバイダ(twitterとかgithubとか)を使って認証するライブラリです。みたいな感じだと思います

準備のためにGemfile、configに設定を記述します。"API_KEY", "API_SECRET"https://apps.twitter.com/ から取得できる値に置き換える必要があります。 値を取得する際に、登録フォームにアプリケーション情報を入力します。項目の1つに「Callback URL」という任意の入力フォームがあるのですが、これにもなんらかの値を入力してやらないと認証チェックの時に弾かれてしまうようです。また、"API_KEY", "API_SECRET" は多分他人から見られるとよろしくないので、 dotenv など使ってgit管理下から外してやったほうが良いと思います。

# Gemfile
gem 'omniauth-twitter'

# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter, "API_KEY", "API_SECRET"
end

ユーザ認証

/auth/twitterにリダイレクトさせてやると、omniauthが認証に必要な作業を行ってくれるようです。認証の処理が終わった後/auth/:provider/callback宛に認証情報を持ったhashを渡します(という認識で合っているのかな?)。routes.rbの記述により、認証のコールバックがSessionControllerのcreateアクションに割り当てられます。認証が成功したらブラウザ上に情報が表示されると思います。

# 任意のview
= link_to "Sign in with Twitter", "/auth/twitter"

# config/routes.rb
get '/auth/:provider/callback', to: 'sessions#create'

# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def create
    render text: request.env['omniauth.auth']
  end
end

それでは、実際に取得した情報をUserとして登録してみます。ネットで見つけた情報をなぞっただけなので適切な方法かは分からないのですが、認証後得られたhash値を見て:provider:uidが既存のUserと一致する場合はそのユーザでログインして、一致しない時はhash値を元にユーザを作成してログインします。最低限:provider:uidだけ保存しておけばログインできると思いますが、今回は画面上にユーザ名と画像を表示したかったので[:info][:name][:info][:image]を、またアプリ上からつぶやきたかったため、それに必要となるauth[:credentials][:token]auth[:credentials][:secret]の情報も保存しました。これでユーザ登録とログイン機能が実装できました。

# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def create
    user = User.find_by(provider: auth[:provider], uid: auth[:uid]) || User.create_from_auth!(auth)
    session[:user_id] = user.id
    redirect_to '/', notice: 'sign in!'
  end

  private

  def auth
    request.env['omniauth.auth']
  end
end
# app/models/user.rb
class User < ActiveRecord::Base
  def self.create_from_auth!(auth)
    create! do |user|
      user.provider = auth[:provider]
      user.uid = auth[:uid]
      user.name = auth[:info][:name]
      user.image = auth[:info][:image]
      user.token = auth[:credentials][:token]
      user.secret = auth[:credentials][:secret]
    end
  end
end

次回は「アプリ上からつぶやく編」を書くかもしれません

参考