ในบทเรียนนี้ คุณจะได้เรียนรู้วิธีให้ผู้ใช้ล็อกอินแอปพลิเคชันด้วยบัญชี Twitter ทำได้ง่ายด้วย OAuth และ OmniAuth-Twitter ซึ่งเป็นกลยุทธ์ (strategy) ของ Twitter สำหรับ OmniAuth
มาเริ่มกันเลย!
เริ่มต้น
สร้างแอป Rails ใหม่ จากเทอร์มินัล รันคำสั่ง:
rails new Tuts-Social -T
เปิด Gemfile เพิ่ม bootstrap gem:
#Gemfile ... gem 'bootstrap-sass'
ติดตั้งเจม:
bundle install
เปลี่ยนชื่อ app/assets/stylesheets/application.css เป็น app/assets/stylesheets/application.scss
เพิ่มโค้ด import bootstrap:
#app/assets/stylesheets/application.scss ... @import 'bootstrap-sprockets'; @import 'bootstrap';
สร้าง partial _navigation.html.erb ใน app/views/layouts สำหรับ navigation bar:
#app/views/layouts/_navigation.html.erb
<nav class="navbar navbar-inverse">
<div class="container">
<div class="navbar-header">
<%= link_to 'Tuts Social', root_path, class: 'navbar-brand' %>
</div>
<div id="navbar">
<ul class="nav navbar-nav pull-right">
<li><%= link_to 'Home', root_path %></li>
</ul>
</div>
</div>
</nav>
Render navigation ใน application layout:
#app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Tuts Social</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<%= render "layouts/navigation" %>
<div id="flash">
<% flash.each do |key, value| %>
<div class="flash <%= key %>"><%= value %></div>
<% end %>
</div>
<div class="container-fluid">
<%= yield %>
</div>
</body>
</html>
สร้าง PagesController พร้อม action index:
rails generate controller Pages index
แก้ไขวิว index:
#app/views/pages/index.html.erb <div class="jumbotron"> <h1>Welcome to Tuts Social!</h1> <p>Thanks for checking us out!</p> </div>
คลาส jumbotron เป็นคอมโพเนนต์ของ Bootstrap สำหรับแสดงข้อความการตลาด
เพิ่ม root_path ใน routes:
#config/routes.rb Rails.application.routes.draw do root to: "pages#index" end
ตั้งค่า OmniAuth-Twitter
สร้างแอป Twitter ใหม่ที่ Twitter Developer Portal กรอกรายละเอียด ตั้งค่า Callback URL เป็น https://127.0.0.1:3000/auth/twitter/callback สำหรับเครื่องท้องถิ่น
หลังสร้างแล้ว ไปที่แท็บ Keys and Access Tokens คัดลอก Consumer Key และ Consumer Secret เก็บไว้ปลอดภัย
Callback URL คือ URL ที่ผู้ใช้จะถูก redirect กลับมาหลังยืนยันตัวตน ทุก OmniAuth strategy คาดหวัง callback URL เป็น “/auth/:provider/callback” โดย :provider คือชื่อกลยุทธ์ (ในที่นี้คือ "twitter")
เพิ่มเจม omniauth-twitter ใน Gemfile:
#Gemfile ... gem 'omniauth-twitter'
สร้าง initializer สำหรับ OmniAuth ใน config/initializers/omniauth.rb:
#config/initializers/omniauth.rb Rails.application.config.middleware.use OmniAuth::Builder do provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'] end
ใช้ environment variables เพื่อเก็บ key อย่า commit ขึ้น public repo ใช้ dotenv-rails:
#Gemfile ... group :development, :test do ... gem 'dotenv-rails' ... end
ติดตั้ง:
bundle install
สร้างไฟล์ .env ในโฟลเดอร์รากโปรเจกต์:
#.env TWITTER_KEY=xxxxxxxxxxxxxx TWITTER_SECRET=xxxxxxxxxxxxxx
เพิ่ม .env ใน .gitignore:
#.gitignore ... # Ignore .env used for storing keys and access tokens .env
ตอนนี้ key และ token ปลอดภัยแล้ว!
เพิ่ม route สำหรับ callback:
#config/routes.rb ... get '/auth/:provider/callback', to: 'sessions#create'
เพิ่มลิงก์ Sign in with Twitter ใน navigation:
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Tuts Social</a>
</div>
<div class="collapse navbar-collapse" id="navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><%= link_to 'Home', root_path %></li>
<% if current_user %>
<li>Signed in as <%= current_user.name %></li>
<% else %>
<li><%= link_to "Sign in with Twitter", "/auth/twitter" %></li>
<% end %>
</ul>
</div>
</div>
</nav>
แสดงลิงก์ล็อกอิน Twitter เฉพาะเมื่อยังไม่ล็อกอิน
สร้าง Sessions
ต้องมี SessionsController จัดการล็อกอิน สร้างไฟล์ app/controllers/sessions_controller.rb:
#app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
@user = User.find_or_create_from_auth_hash(auth_hash)
session[:user_id] = @user.id
redirect_to root_path
end
protected
def auth_hash
request.env['omniauth.auth']
end
end
Action create สร้าง session ให้ผู้ใช้ล็อกอินได้
ต้องมีเมธอด current_user ตรวจสอบสถานะล็อกอิน เพิ่มใน app/controllers/application_controller.rb:
#app/controllers/application_controller.rb ... def current_user @current_user ||= User.find(session[:user_id]) if session[:user_id] end helper_method :current_user ...
User Model
สร้างโมเดล User:
rails generate model User provider:string uid:string name:string token:string secret:string profile_image:string
ไฟล์ migration จะออกมาแบบนี้:
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :provider
t.string :uid
t.string :name
t.string :token
t.string :secret
t.string :profile_image
t.timestamps
end
end
end
รัน migration:
rake db:migrate
แก้ไขโมเดล User:
#app/models/user.rb
class User < ApplicationRecord
def self.find_or_create_from_auth_hash(auth_hash)
user = where(provider: auth_hash.provider, uid: auth_hash.uid).first_or_create
user.update(
name: auth_hash.info.nickname,
profile_image: auth_hash.info.image,
token: auth_hash.credentials.token,
secret: auth_hash.credentials.secret
)
user
end
end
โค้ดเก็บข้อมูลผู้ใช้: name, profile_image, token, secret หากต้องการเพิ่มดูที่หน้า OmniAuth-Twitter
ลบ Sessions (Logout)
เพิ่ม action destroy ใน SessionsController:
#app/controllers/sessions_controller.rb
...
def destroy
if current_user
session.delete(:user_id)
flash[:success] = "Successfully logged out!"
end
redirect_to root_path
end
...
เพิ่มลิงก์ Log Out ใน navigation:
#app/views/layouts/_navigation.html.erb
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Tuts Social</a>
</div>
<div class="collapse navbar-collapse" id="navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><%= link_to 'Home', root_path %></li>
<% if current_user %>
<li>Signed in as <%= current_user.name %></li>
<li><%= link_to 'Log Out', logout_path, method: :delete %></li>
<% else %>
<li><%= link_to "Sign in with Twitter", "/auth/twitter" %></li>
<% end %>
</ul>
</div>
</div>
</nav>
อัปเดต routes:
#config/routes.rb ... delete '/logout', to: 'sessions#destroy' ...
เริ่มเซิร์ฟเวอร์ และเปิด https://localhost:3000 เพื่อทดสอบ
สรุป
ในบทเรียนนี้ คุณได้เรียนรู้การเปิดใช้งาน OmniAuth-Twitter ใน Rails การดึงข้อมูลผู้ใช้จาก OmniAuth-Twitter ใน User Model และสร้าง SessionController จัดการล็อกอิน/ล็อกเอาท์ หวังว่าคุณจะสนุก ในอนาคตจะมีบทเรียนสำหรับ Facebook, Google, LinkedIn ด้วย