Ruby on Railsを触ってみる ④devise+OmniAuthでTwitter認証
今のままではユーザー関係なく、アップロードされたツイートがすべて参照できてしまう。そこでユーザ認証機能を追加して、ユーザ自身がアップロードしたツイートのみを表示できるようにしたい。
ユーザ認証はdeviseというライブラリが定番らしい。そしてTwitter認証を行うにはOmniAuthを使うのが定番らしい。早速これらを導入してみようと思う。
Gemfileを編集する。
$ git diff Gemfile diff --git a/Gemfile b/Gemfile index 0b509d6..587addf 100644 --- a/Gemfile +++ b/Gemfile @@ -48,3 +48,8 @@ end # Pagenation gem 'kaminari' + +# User Authentication +gem 'devise' +gem 'omniauth-twitter' +
bundle installを行う。
$ bundle install
deviseのインストール。
$ rails g devise:install
認証用モデルUserを作成する。
$ rails g devise user
migrationファイルを編集しておく。TrackableとOmniauthableがあればいいみたいなので、不要な箇所は削除。uidにindexを張る。
class DeviseCreateUsers < ActiveRecord::Migration def change create_table(:users) do |t| ## Trackable t.integer :sign_in_count, :default => 0, :null => false 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 end end
これでdb:migrateを行う。
$ rake db:migrate
予め取得していたTwitter APIのtokenをconfiginitialize/devise.rbに追記します。
config.omniauth :twitter, '<ID>', '<SECRET>', :display => 'popup' end
twitterからのコールバックのためのルーティングを設定する。 また、サインイン後、サインアウト後にrootに飛ばされるため、rootをひとまず設定しておく。
$ git diff config/routes.rb diff --git a/config/routes.rb b/config/routes.rb index 379330e..a18f6b9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,6 +5,14 @@ Twice::Application.routes.draw do post 'import_csv' end end + + devise_for :users, :controllers => { :omniauth_callbacks => "omniauth_callbacks" } + root :to => 'tweets#index' + + 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
コールバック用のコントローラを作成する。 登録済みのユーザの場合は認証、登録済みでない場合はUsersテーブルに登録を行ってくれるはず。
/* omniauth_callbacks_controller.rb */ class OmniauthCallbacksController < Devise::OmniauthCallbacksController def twitter # You need to implement the method below in your model @user = User.find_for_twitter_oauth(request.env["omniauth.auth"]) 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
登録済みかどうかのチェックをUserモデル内に定義する。
class User < ActiveRecord::Base # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :trackable, :omniauthable def self.find_for_twitter_oauth(auth) 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, password:Devise.friendly_token[0,20] ) end user end end
ログインボタンをnavigation barに追加する。
$ git diff app/views/layouts/application.html.erb diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 67644c1..22313f4 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -52,6 +52,11 @@ <li><%= link_to "Link1", "/path1" %></li> <li><%= link_to "Link2", "/path2" %></li> <li><%= link_to "Link3", "/path3" %></li> + <% if user_signed_in? %> + <li><%= link_to "ログアウト", (destroy_user_session_path) %></li> + <% else %> + <li><%= link_to "ログイン", (user_omniauth_authorize_path :twitter) %></li> + <% end %> </ul> </div><!--/.nav-collapse --> </div>
Usersテーブルを確認すると、ちゃんと追加されていた。