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 endCreate 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 endNow 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 .