Trong hướng dẫn này, bạn sẽ học cách cho phép người dùng ứng dụng đăng nhập bằng tài khoản Twitter. Việc này trở nên dễ dàng nhờ các công cụ như OAuth.
Bạn sẽ sử dụng OmniAuth-Twitter, chứa chiến lược Twitter cho OmniAuth.
Hãy bắt đầu nào!
Bắt Đầu
Khởi tạo bằng cách tạo ứng dụng Rails. Từ terminal, chạy lệnh:
rails new Tuts-Social -T
Mở Gemfile và thêm gem bootstrap.
#Gemfile ... gem 'bootstrap-sass'
Cài gem bằng lệnh:
bundle install
Đổi tên app/assets/stylesheets/application.css thành app/assets/stylesheets/application.scss.
Khi xong, thêm các dòng sau để import bootstrap:
#app/assets/stylesheets/application.scss ... @import 'bootstrap-sprockets'; @import 'bootstrap';
Tạo partial tên _navigation.html.erb chứa code điều hướng; đặt trong thư mục app/views/layouts.
Nhập code dưới vào IDE. Nó dùng Bootstrap để tạo thanh điều hướng cho ứng dụng.
#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>
Để navigation được dùng, cần render nó trong application layout. Sửa layout ứng dụng như sau:
#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>
Tạo PagesController với action index bằng lệnh:
rails generated controller Pages index
Trong view index tạo ra, sửa thành:
#app/views/pages/index.html.erb <div class="jumbotron"> <h1>Welcome to Tuts Social!</h1> <p>Thanks for checking us out!</p> </div>
Ở trên dùng class jumbotron—component Bootstrap cho phép mở rộng viewport để hiển thị thông điệp marketing. Xem thêm tại tài liệu Bootstrap.
Mở file routes để thêm root_path:
#config/routes.rb Rails.application.routes.draw do # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html root to: "pages#index" end
Thiết Lập OmniAuth-Twitter
Cần tạo ứng dụng Twitter mới. Vào trang Twitter Developer để tạo. Nhập các chi tiết cần thiết, tương tự như ảnh chụp màn hình dưới.


Đối với callback URL, nhập địa chỉ website cộng với "auth/twitter/callback". Nếu chạy local, callback URL là: https://127.0.0.1:3000/auth/twitter/callback.
Bạn sẽ được chuyển đến trang thông tin app trên Twitter. Vào tab Keys and Access Tokens để lấy key. Copy Consumer Key và Consumer Secret lưu nơi an toàn—sẽ dùng ngay.
Callback URL là URL người dùng được chuyển hướng đến sau khi xác thực và cấp quyền thành công (request sẽ chứa dữ liệu user và token). Tất cả chiến lược OmniAuth mong đợi callback URL bằng “/auth/:provider/callback”. :provider lấy tên chiến lược. Ở đây chiến lược là "twitter" như khai báo trong initializer.
Mở Gemfile thêm gem omniauth-twitter:
#Gemfile ... gem 'omniauth-twitter'
Tạo initializer cho OmniAuth trong thư mục config/initializers. File này chứa cấu hình OmniAuth. Làm giống như sau:
#config/initializers/omniauth.rb Rails.application.config.middleware.use OmniAuth::Builder do provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'] end
Lúc này cần dùng key và access token đã lưu. Cần giữ an toàn để không push lên repo công khai khi commit code.
Sẽ dùng gem cho việc này. Mở Gemfile thêm gem dưới. Thêm vào group development, test:
#Gemfile ... group :development, :test do ... gem 'dotenv-rails' ...
Cài gem:
bundle install
Trong thư mục gốc ứng dụng, tạo file .env.
Mở và thêm key, token như sau:
#.env TWITTER_KEY=xxxxxxxxxxxxxx TWITTER_SECRET=xxxxxxxxxxxxxx
Mở .gitignore thêm file vừa tạo:
#.gitignore ... # Ignore .env used for storing keys and access tokens .env
Vậy là key và token an toàn! Để tìm hiểu thêm về dotenv-rails, xem trang GitHub.
Cập nhật route. Mở file routes thêm route sau:
#config/routes.rb ... get '/auth/:provider/callback', to: 'sessions#create'
Thêm link đăng nhập Twitter vào navigation. Mở file navigation sửa thành:
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<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>
Từ trên, chỉ hiển thị link đăng nhập Twitter khi user chưa đăng nhập.
Tạo Sessions
Cần session controller để xử lý đăng nhập user. Tạo file trong thư mục controllers, nội dung như sau:
Action create giúp tạo session cho user để họ đăng nhập vào ứng dụng. Không có này thì user không có cách nào đăng nhập.
#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
Cần phương thức current_user lúc này. Nó giúp kiểm tra user đã đăng nhập hay chưa.
Mở app/controllers/application_controller.rb thêm:
#app/controllers/application_controller.rb ... def current_user @current_user ||= User.find(session[:user_id]) if session[:user_id] end helper_method :current_user ...
Model User
Tạo model User. Chạy lệnh:
rails generated model User provider:string uid:string name:string token:string secret:string profile_image:string
Sẽ sinh migration file như sau:
#xxxxxx_create_users.rb
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
Migrate database:
rake db:migrate
Mở model User sửa thành:
#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
Code trên lưu một số thông tin user: name, profile_image, token, secret. Nếu ứng dụng cần thêm thông tin, xem trang OmniAuth-Twitter.
Xóa Sessions (Đăng Xuất)
Trong ứng dụng, cần cho user đăng xuất. Cần action destroy trong SessionsController và thêm link vào navigation.
Thêm action destroy vào 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
...
Thêm link đăng xuất vào navigation, navigation thành:
#app/views/layouts/_navigation.html.erb
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<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>
Mở config/routes.rb cập nhật route với action vừa tạo:
#config/routes.rb ... delete '/logout', to: 'sessions#destroy' ...
Khởi động rails server và truy cập https://localhost:3000 để xem kết quả.
Kết Luận
Trong hướng dẫn này bạn đã học cách bật OmniAuth-Twitter trong ứng dụng Rails. Bạn thấy cách lấy dữ liệu user bằng OmniAuth-Twitter, thực hiện ở model User. Bạn tạo SessionControllers xử lý đăng nhập/đăng xuất user khỏi ứng dụng.
Hy vọng bạn thích. Tương lai sẽ hướng dẫn làm tương tự cho Facebook, Google, LinkedIn.