In this tutorial, you will learn how to allow users of your application to log in using their Twitter account. Doing this has been made easy with tools such as OAuth.
You will make use of OmniAuth-Twitter, which contains the Twitter strategy for OmniAuth.
Let's dive in!
Start by generating your Rails application. From your terminal, run the command to do so:
rails new Tuts-Social -T
Open up your Gemfile and add the bootstrap gem.
#Gemfile ... gem 'bootstrap-sass'
Install the gem by running the command:
When done, add the following lines of code to import bootstrap.
#app/assets/stylesheets/application.scss ... @import 'bootstrap-sprockets'; @import 'bootstrap';
Create a partial named
_navigation.html.erb to hold your navigation code; the partial should be located in the
Enter the code below into an IDE. It uses Bootstrap to create a navigation bar for your application.
#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>
For the navigation to be used, you need to render it in your application layout. Tweak your application layout to look like what I have below.
PagesController with an index action by entering the command below into your terminal.
rails generated controller Pages index
In the index views generated, edit it to look like this.
#app/views/pages/index.html.erb <div class="jumbotron"> <h1>Welcome to Tuts Social!</h1> <p>Thanks for checking us out!</p> </div>
In the above code, we make use of a class called
jumbotron—this is a Bootstrap component that allows us extend the viewport to showcase a marketing message. You can find more about it from the Bootstrap documentation.
Open your routes file to add your
#config/routes.rb Rails.application.routes.draw do # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html root to: "pages#index" end
You need to create a new Twitter application. Go to this page in the Twitter Developer pages to create one. Enter all the necessary details, similar to what I have in the screenshot below.
For the callback URL, enter your website's address plus "auth/twitter/callback". If you happen to be on a local machine, your callback URL should be this:
You will be redirected to the app’s information page on Twitter. Navigate to the Keys and Access Tokens tab to get your keys. Copy the Consumer Key and Consumer Secret and paste them in a safe place—we will make use of them shortly.
The callback URL is the URL where a user will be redirected to inside the app after successful authentication and approved authorization (the request will also contain the user’s data and token). All OmniAuth strategies expect the callback URL to equal “/auth/:provider/callback”.
:provider takes the name of the strategy. In this case, the strategy will be "twitter" as you will list in the initializer.
Open up your
Gemfile to add the
#Gemfile ... gem 'omniauth-twitter'
Now create an initializer for OmniAuth in your config/initializers directory. This will hold the configuration for OmniAuth. Make it look like what I have below.
#config/initializers/omniauth.rb Rails.application.config.middleware.use OmniAuth::Builder do provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'] end
At this point you'll need to make use of the keys and access tokens you stored safely. You need to keep these safe as you do not want to push them to a public repository when you commit your code.
You will make use of a gem for this. Open your Gemfile again and add the gem below. Add it to your Gemfile like so:
#Gemfile ... group :development, :test do ... gem 'dotenv-rails' ...
To install the gem, run.
In the home directory of your application, create a file called
Open it and add your keys and tokens like so:
#.env TWITTER_KEY=xxxxxxxxxxxxxx TWITTER_SECRET=xxxxxxxxxxxxxx
.gitignore and add the file you just created.
#.gitignore ... # Ignore .env used for storing keys and access tokens .env
With this done, your keys and access tokens are safe! To learn more on how to use
-rails, refer to the GitHub page.
Time to work on your route. Open up your routes file and add the route below.
#config/routes.rb ... get '/auth/:provider/callback', to: 'sessions#create'
You need to add the link for Twitter sign-in to your navigation. Open your navigation file and tweak it to look like this.
<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>
From the above, you want to show the link to log in with Twitter only when the user is not signed in.
You'll need a session controller to handle the logging in of users. Create a file for that in your controllers directory; this is how it should look.
The create action helps create a session for users so they can be logged into your application. Without this, users have no means of logging in.
#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
You'll need a
current_user method at this point. This will help you check if a user is logged in or out.
app/controllers/application_controller.rb and add the following.
#app/controllers/application_controller.rb ... def current_user @current_user ||= User.find(session[:user_id]) if session[:user_id] end helper_method :current_user ...
Now generate a model for your Users. Run the command to do so.
rails generated modoel User provider:string uid:string name:string token:string secret:string profile_image:string
That should generate a migration file that looks like this.
#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
Now migrate your database by running:
Open up your User model and make it look like this:
#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
The code above stores some information belonging to the user. This includes the name, profile_image, token, and secret of the user. If your application requires more than this, you can check out the OmniAuth-Twitter page.
In your application, you want to provide users the ability to log out. You will need a
destroy action in your
SessionsController for this to work. Then a link will be added to your navigation.
destroy action to your
#app/controllers/sessions_controller.rb ... def destroy if current_user session.delete(:user_id) flash[:success] = "Sucessfully logged out!" end redirect_to root_path end ...
Then add this link for logging out to your navigation, so your navigation looks like this.
#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>
Open up your config/routes.rb to update your routes with the action you just created.
#config/routes.rb ... delete '/logout', to: 'sessions#destroy' ...
Start up your rails server and point your browser to http://localhost:3000 to see what you have.
In this tutorial you have learned how to enable OmniAuth-Twitter in your Rails application. You saw how to get the data of users using OmniAuth-Twitter, which you did in your User model. You were able to create
SessionControllers to handle the logging in and out of users from your application.
I hope you enjoyed it. In the future, you will see how to do the same for Facebook, Google, and LinkedIn.