In the last post , we have discussed how to get api keys and access for multiple social media platform .In this post we will to setup rails to integrate these applications .
Code SetUp:
Now its Time to Set Up Rails Application with MongoDB , Rails & Omniauth Gem(s).
we will be using “ruby 2.1.1p76” with “Rails 4.1.0” for our application.
Step 1:
In Gem file add the following Gems:
gem 'rails', '4.1.0' gem 'mongoid', git: 'https://github.com/mongoid/mongoid.git' gem 'devise' gem 'bson_ext' gem 'omniauth' gem 'omniauth-facebook' gem 'omniauth-linkedin' gem 'omniauth-twitter' gem "omniauth-google-oauth2" gem 'twitter' gem "linkedin" gem 'oauth2'Step 2: Follow the link and install devise gem to your application. For Omniauth with devise follow the link which will be usefull for development and debugging your application. Step 3: Include required Gems in your initializers/devise.rb file and add your API KEYS with API Secret.
require 'devise/orm/mongoid' require 'omniauth-twitter' require 'omniauth-google-oauth2' require 'omniauth-linkedin' require 'omniauth-facebook' require 'omniauth-github'Configuring API Keys:
config.omniauth :twitter, "API KEY", "API SECRET" config.omniauth :linkedin, "API KEY", "API SECRET", :scope => 'r_basicprofile r_emailaddress rw_nus' config.omniauth :facebook, 'API KEY', 'API SECRET' config.omniauth :google_oauth2, 'API KEY', 'API SECRET'Add the following links to devise registrations/new or shared/_links.html.erb Open Up Your User Model and Configure it as described below , fields for mongo db can be configured as per your requirement :
class User
include Mongoid::Document
devise :omniauthable, :omniauth_providers => [:facebook,:twitter,:linkedin,:google_oauth2]
embeds_one :user_linkedin_connection, :class_name => 'User::LinkedinConnection'
embeds_one :user_twitter_connection, :class_name => 'User::TwitterConnection'
# Configured for Getting mongo key from Session in rails 4 (Mongoid)
class << self
def serialize_from_session(key, salt)
record = to_adapter.get(key.first["$oid"]) if key.present? # to_adapter.get(key.to_s)
record if record && record.authenticatable_salt == salt
end
end
def self.connect_to_linkedin(auth)
self.provider = auth.provider
self.uid = auth.uid
self.user_linkedin_connection = User::LinkedinConnection.new(:token => auth["extra"]["access_token"].token, :secret => auth["extra"]["access_token"].secret)
unless self.save
return false
end
true
end
def self.disconnect_from_linkedin!
self.provider = nil
self.uid = nil
self.user_linkedin_connection = nil
self.save!
end
def self.find_for_linkedin_oauth(auth, signed_in_resource=nil)
@user = User.where(:provider => auth.provider, :uid => auth.uid).first
if @user
@user.connect_to_linkedin(request.env["omniauth.auth"])
sign_in_and_redirect @user, :event => :authentication
set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
else
flash[:notice] = "Couldn't find a user connected to your LinkedIn account. Please sign in and then connect your account to LinkedIn."
redirect_to new_user_session_url
end
end
def self.find_for_facebook_oauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.name = auth.info.name # assuming the user model has a name
end
end
def self.find_for_google_oauth2(access_token, signed_in_resource=nil)
data = access_token.info
user = User.where(:email => data["email"],:provider => "Google").first
unless user
user = User.create( name: data["name"],email: data["email"],provider: "Google", password: Devise.friendly_token[0,20] )
end
user
end
def self.find_for_github_oauth(auth)
record = where(provider: auth.provider, uid: auth.uid.to_s).first
record || create(provider: auth.provider, uid: auth.uid, email: auth.info.email, password: Devise.friendly_token[0,20], name: auth.info.name )
end
end
Create two More files named linkedin_connection.rb and twitter_connection.rb inside app/models/user/ which will contain the token and secret provided from provider.
linkedin_connection.rb:
class User::LinkedinConnection include Mongoid::Document include Mongoid::Timestamps embedded_in :user field :token field :secret endtwitter_connection.rb:
class User::TwitterConnection include Mongoid::Document field :token include Mongoid::Timestamps field :secret embedded_in :user endOnce we get a Success request from Provider , response moves on to omniauth call_back controller where we need to store the response and maintain the session. Create a omniauth_callback controller and paste the code as provided below:
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
before_filter :authenticate_user!
# Linkedin authentication
def linkedin
@user = User.where(:provider => request.env["omniauth.auth"].provider, :uid => request.env["omniauth.auth"].uid).first
if @user.present?
sign_in_and_redirect @user, :event => :authentication
set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
else
auth = request.env["omniauth.auth"]
@user = User.new #create new user to save in the database
@user.email= auth.info.email #save user email
@user.provider = auth.provider
@user.uid = auth.uid
@user.user_linkedin_connection = User::LinkedinConnection.new(:token => auth["extra"]["access_token"].token, :secret => auth["extra"]["access_token"].secret)
@user.save(:validate => false) #password for the linkdin to be stored
sign_in_and_redirect @user, :event => :authentication
set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
end
end
# Facebook authentication
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
@user = User.find_for_facebook_oauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
# Twitter authentication
def twitter
@user = User.where(:provider => request.env["omniauth.auth"].provider, :uid => request.env["omniauth.auth"].uid).first
if @user.present?
sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
else
auth = request.env["omniauth.auth"] # contains all the information about the user login profile.
@user = User.create(name: auth.extra.raw_info.name,
provider: auth.provider,
uid: auth.uid,
email: auth.uid+"@twitter.com", #create user email
password: Devise.friendly_token[0,20],
user_twitter_connection: User::TwitterConnection.new(:token => auth.credentials.token, :secret => auth.credentials.secret )
)
sign_in_and_redirect @user, :event => :authentication
set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
end
end
# Google authentication
def google_oauth2
# You need to implement the method below in your model (e.g. app/models/user.rb)
@user = User.find_for_google_oauth2(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
set_flash_message(:notice, :success, :kind => "Google") if is_navigational_format?
# flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
# sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
else
session["devise.google_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
Now we are Good to Go ahead and start authenticating with social websites in our Rails app.
Note:
• Application status in Provider Settings should be live
• Call back URL should match your application routes
• It is Good to go with Storing session in DB as sometimes cookie_store fails when a logged in user fetches request from provider.
Thanks to Santosh for wroting this post .
