追記:Qiita「TwitterAPI Devise連携/グラフ可視化/データの効率的格納/API高速化」 にて続きを書きました。
qiitaにもある、「twitterでログイン」を実装します。
devise(railsのユーザー認証用gem)を使ってtwitter,facebookなどのOAuth認証。
今回はOAuth認証のみでdevise本来の追加認証はしません。tokenも使いません。
deviseの導入から解説していきます。
環境
- ruby(1.9.3)
 - rails(3.2.3)
 - devise(2.0.4)
 - omniauth (1.1.0)
 - omniauth-oauth (1.0.1)
 - omniauth-oauth2 (1.0.2)
 - omniauth-facebook (1.3.0)
 - omniauth-twitter (0.0.9)
 
devise+omniauth認証
まずはdeviseの導入。https://github.com/plataformatec/devise を参考に。
1. Gem
以下をgemに追加
gem 'devise'
# omniauth
gem 'omniauth-facebook'
gem 'omniauth-twitter'
2. devise導入
$ bundle install
$ rails g devise:install
 config/inistializer/devise.rb (設定ファイル)作成
$ rails g devise user
 認証用モデル作成。今回はUserモデルにした。
$ rails g migration AddOmniToUser uid:integer
 migrationファイルにて、omniauth認証用カラム追加
3. deviseのmigration設定
migrationファイルを編集します。Omniauthableのためのカラムを追加します。
今回はtrackable以外の機能は使用しないので、その他はコメントアウトしてください。使う場合はお好みで。
trackableはログイン回数などを記録する機能です。
facebookはuidが非常に長いので、bigintにすることに注意してください!(3日はまりました)
class DeviseCreateUsers < ActiveRecord::Migration
  def change
    create_table(:users) do |t|
      ## Trackable
      t.integer  :sign_in_count, :default => 0
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip
      ##Omniauthable
      t.integer :uid, :limit => 8 #bigintにする
      t.string :name
      t.string :provider
      t.string :password
      t.timestamps
    end
    add_index :users, :uid,  :unique => true
$ rake db:migrate
4. deviseのモデル編集
Userモデルを編集します。omniauthableにし、使わない機能をコメントアウトしましょう。
class User < ActiveRecord::Base
   devise :trackable, :omniauthable
   attr_accessible :name, :password, :uid, :provider
end
5.developerサイトに登録
OAuth認証したいサイトにてアプリを作成し、IDとsecretを取得します。
twitter,facebookのdeveloperサイトでの作成法を解説。
サイトのURLを設定するので、development,production用に2つ作ると良いです。
(ここで指定するURLが異なると動かない場合があります!)
http://developers.facebook.com/
一番上のバーにある「アプリ」→右上「新しいアプリケーションを作成」
name,descriptionを記述。
herokuで作るかどうか選べますが、今回関係ないのでチェックしません。
アプリの個別ページに飛ぶので、
「アプリをFacebookに結合する方法を選択してください」でサイトのURLを記述します。
http://localhost:3000/
とでもしておきましょう。
App IDとApp Secretをメモっておきます。
https://dev.twitter.com/
ログイン後、右上のアイコンから「My Application」→「Create a New Application」で詳細を入力します。
name,descriptionを記述。websiteには実際に動かすURLのルートを。Callback URLにも同様にURLを記述。
Consumer key,Consumer secretをメモってください。
- 注意:http://localhost:3000/ だとエラー出ます。ドメインやIPを入れてください。(なお
twitterの場合、facebookと異なり、ここのURL指定が適当でも動いたりします) - 注意:Callback URL(ログイン完了後のredirect URL)を記述しないと動きません。なぜかここで記述したURLにはredirectされないので、なんでもいいので記述を。
 
6. deviseのconfig編集
OAuth認証のために、deviseを設定します。
config/initializer/devise.rb
に記述してもいいのですが、開発環境と本番環境を分けたいため、development.rbに記述します。
.
.
.
  Devise.setup do |config|devise@example.com"
    config.omniauth :facebook, '{ID}', '{SECRET}', :scope => 'email,user_birthday', :display => 'popup'
    config.omniauth :twitter, '{ID}', '{SECRET}', :display => 'popup'
  end
facebookではメールと誕生日も取得できるようにしてありますが、不要な場合はscopeを消してください。
7. Userモデル再編集
各種関数を追加します。
.
.
.
  def self.new_with_session(params, session)
    super.tap do |user|
      if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
        user.email = data["email"]
      end
    end
  end
  
  
  def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
    user = User.where(:provider => auth.provider, :uid => auth.uid).first
    unless user
      user = User.create(name:auth.extra.raw_info.name,
                          provider:auth.provider,
                          uid:auth.uid,
 #                          email:auth.info.email, #emailを取得したい場合は、migrationにemailを追加してください。
                          password:Devise.friendly_token[0,20]
                          )
    end
    user
  end
  
  
  def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
    user = User.where(:provider => auth.provider, :uid => auth.uid).first
    unless user
      user = User.create(name:auth.info.nickname,
                          provider:auth.provider,
                          uid:auth.uid,
#                          email:auth.extra.user_hash.email, #色々頑張りましたがtwitterではemail取得できません
                          password:Devise.friendly_token[0,20]
                          )
    end
    user
  end
8. Controller設定
app/controllers/users/omniauth_callbacks_controller.rbを作成し、編集します。
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    # You need to implement the method below in your model
    @user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
    if @user.persisted?
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
      sign_in_and_redirect @user, :event => :authentication
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end
  
  def twitter
    # You need to implement the method below in your model
    @user = User.find_for_twitter_oauth(request.env["omniauth.auth"], current_user)
    if @user.persisted?
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Twitter"
      sign_in_and_redirect @user, :event => :authentication
    else
      session["devise.twitter_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end
end
9. route定義
config/routes.rbを設定します。
ログイン後にはrootに飛ばされるので、root定義もすると良いです。
  root :to => 'yourapp#index'
  devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
  devise_scope :user do
    get 'sign_in', :to => 'devise/sessions#new', :as => :new_user_session
    get 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_user_session
  end
.
.
.
10. 確認
viewを作り、サーバーをたちあげて確認。
            <ul class="nav">
              <% if user_signed_in? %>
                <li><%= link_to 'ログアウト', destroy_user_session_path %></li>
              <% else %>
                <li><%= link_to "facebookでログイン", user_omniauth_authorize_path(:facebook) %></li>
                <li><%= link_to "twitterでログイン", user_omniauth_authorize_path(:twitter)  %></li>
              <% end %>
                
            </ul>
Invalid URI error が出る場合は、twitterやfacebookのURL指定が間違っています。
facebookの場合は、設定変更の反映に時間がかかる場合があります。
どうしてもダメだったらfacebook上のアプリを作りなおしてください。
11. 最後に
長かったですがお疲れ様でした!
他のOAuth認証も、似たような形で追加してください。