Server --> Credentials --> Twitter Server <-- Tokens <-- Twitter Server --> Redirect --> Twitter Server <-- Info <-- Twitter
- require a Gem
- we're using gem: omniauth
(https://github.com/intridea/omniauth)
Name: Awesome Answer - Jan 2016 (must be unique) Description: Awesome Answer Application website: http://127.0.0.1:3000 Callback URL: http://127.0.0.1:3000/callbacks/twitter
Note: Someone created a service, so you can to point to local host.
lvh.me:3000
Select "Read and Write" (so you can tweet on user's behalf)
app_keys.rb
ENV["twitter_consumer_key"] = "...." ENV["twitter_consumer_secret"] = "..."
app_key.rb.example ENV["email_user_name"] = "XXX" ENV["email_password"] = "XXX" ENV["twitter_consumer_key"] = "XXX" ENV["twitter_consumer_secret"] = "XXX"
Need to find specific omniauth for specific site.
ie. omniauth-twitter
(https://github.com/arunagw/omniauth-twitter)
gem 'omniauth-twitter'
- bundle
config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
# provider :twitter, "API_KEY", "API_SECRET"
provider :twitter, ENV["twitter_consumer_key"], ENV["twitter_consumer_secret"]
end
get "/auth/twitter", as: :sign_in_with_twitter
get "/auth/twitter/callback" => "callbacks#twitter"
routes
<%= link_to "Sign In With Twitter", sign_in_with_twitter_path %>
bin/rails g controller callbacks
controllers/callbacks_controller.rb
class CallbacksController < ApplicationController
# =============================================
def twitter
# search for the user with their uid/provider, if we find the user then
# we log the user in, otherwise, we create a new user account
omniauth_data = request.env['omniauth.auth']
user = User.where(provider: "twitter", uid: omniauth_data["uid"]).first
if user
sign_in(user)
redirect_to root_path, notice: "Sign in!"
else
# ===========================================
render json: request.env['omniauth.auth']
# ===========================================
# Create the user account
user = User.create_from_twitter(omniauth_data)
sign_in(user)
redirect_to root_path, notice: "Signed in!"
end
end
# =============================================
## Refactor
def twitter
omniauth_data = request.env['omniauth.auth']
## when you see a where, it means move to to the model
# user = User.where(provider: "twitter", uid: omniauth_data["uid"]).first
user = User.find_twitter_user(omniauth_data)
user ||= User.create_from_twitter(omniauth_data)
sign_in(user)
redirect_to root_path, notice: "Signed In!"
end
end
bin/rails g migration add_oauth_fields_to_users uid provider token twitter_secret twitter_raw_data:text
class AddOauthFieldsToUsers < ActiveRecord::Migration
def change
add_column :users, :uid, :string
add_column :users, :provider, :string
add_column :users, :twitter_token, :string
add_column :users, :twitter_secret, :string
add_column :users, :twitter_raw_data, :text
add_index :users, [:uid, :provider] ## Add this
end
end
bin/rake db:migrate
app/models/user.rb
class User < ActiveRecord::Base
# This enables us to sore a Hash to the twitter_data field and retrieve it as a Hash
# Rails will take care of encoding/decoding the data of the Hash to and from the DB
# It will be stored as Text in the DB
serialize :twitter_data, Hash
validates :email, presence: true,
uniqueness: true,
format: /\A([\w+\-]\.?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i,
unless: :from_oauth?
def from_oauth/?
uid.present? && provider.present?
end
def self.create_from_twitter(twitter_data)
name = twitter.data["info"]["name"].split(" ")
# user = User.new(provider: "twitter",
## Choose to create right away
User.create(provider: "twitter",
uid: twitter_data["uid"]
first_name: name[0],
last_name: name[1],
password: SecureRandom.hex,
# it doesn't matter, because user won't be signing it with their password, because using twitter login.
# because password is required, otherwise it won't pass
twitter_token:twitter_data["credentials"]["token"]
twitter_token:twitter_data["credentials"]["secret"]
twitter_raw_data: twitter_data
)
end
def find_twitter_user(omniauth_data)
where(provider: "twitter", uid: omniauth_data["uid"]).first
end
end
gem "twitter"
bundle
user = User.last
client = Twitter::REST::Client.new do |config|
config.consumer_key = ENV["twitter_consumer_key"]
config.consumer_secret = ENV["twitter_consumer_secret"]
config.access_token = user.twitter_token
config.access_token_secret = user.twitter_secret
end
client.follow("stanley321")
client.update("Hello World")
class Question
attr_accessor :tweet_it # this is useful if I have a piece of data to work
# with which we I don't need to store in the DB
#...
def signed_in_with_twitter?
provider.present? && uid.present? && provider == "twitter"
end
end
questions/_form.html.erb
<% if current_user.signed_in_with_twitter? %>
<div>
<%= f.check_box :tweet_it %> Tweet It.
</div>
<% end %>
class QuestionsController < ApplicationController
def create
@question = Question.new question_params
@question.user = current_user
if @question.save
if @question.tweet_it
client = Twitter::REST::Client.new do |config|
config.consumer_key = ENV["twitter_consumer_key"]
config.consumer_secret = ENV["twitter_consumer_secret"]
config.access_token = current_user.twitter_token
config.access_token_secret = current_user.twitter_secret
end
client.update("New Question: #{@question.title}")
end
# all these formats are possible ways to redirect in Rails:
# redirect_to question_path({id: @question.id})
# redirect_to question_path({id: @question})
# redirect_to @question
flash[:notice] = "Question Created Successfully!"
redirect_to question_path(@question)
else
flash[:alert] = "Question wasn't created. Check errors below"
render :new
end
end
private
def question_params
params.require(:question).permit([:title, :body, :category_id, :tweet_it,
{tag_ids: []}])
end
end