users.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
#...field setups for devise...
#
## Provide foundation to support multiple omniauth providers
#
embeds_many :authentications
field :name, :type => String
field :provider, :type => String # TODO: This is a complete hack, better way?
validates_uniqueness_of :email
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
index( { email: 1}, { background: true, unique: true } )
index( { "authentications.provider" => 1 }, { background: true } )
index( { "authentications.uid" => 1 }, { background: true } )
def self.new_with_session(params, session)
#
## When omniauth is generating the user data this method is requested
#
if session["devise.user_attributes"]
auth = session["devise.user_attributes"]
new do |user|
user.name = auth['info']['name'] unless auth['info']['name'].blank?
user.name ||= auth['info']['nickname'] unless auth['info']['nickname'].blank?
user.name ||=auth['info']['first_name'] + ' ' + auth['info']['last_name'] unless auth['info']['first_name'].blank? || auth['info']['last_name'].blank?
user.email = auth['info']['email'] unless auth['info']['email'].blank?
user.provider = auth['provider']
#
## This password stuff is a complete hack
#
user.password, user.password_confirmation = auth['credentials']['token']
user.valid?
end
else
#
## We don't have a omniauth hash, so default to normal devise registration
#
super
end
end
def password_required?
super && provider.blank?
end
def update_with_password(params, *options)
if encrypted_password.blank?
update_attributes(params, *options)
else
super
end
end
Authentication.rb
class Authentication
include Mongoid::Document
field :provider, :type => String, :default => ''
field :uid, :type => String, :default => ''
embedded_in :user
#
## TODO: At the least, we'll want to add in data hooks for FB
## for posting to user's wall, events, etc.
#
end
authentication_controller.rb
class AuthenticationController < Devise::OmniauthCallbacksController
def all
auth = request.env['omniauth.auth']
authentication = User.first.authentications.where(:provider => auth['provider'], :uid => auth['uid']).first
if current_user
#
## we've got a logged in user, lets see if they have already linked their account
#
if current_user.authentications.where(:provider => auth['provider'], :uid => auth['uid'])
flash.notice = "#{auth['provider']} is already linked to your account."
redirect_to '/'
else
current_user.authentications.create!(:provider => auth['provider'], :uid => auth['uid'])
flash.notice = "Sucessfully linked your #{auth['provider']} to your account!"
sign_in_and_redirect current_user #TODO: think about redirection
end
elsif authentication
#
## We don't have a currently logged in user but we do have this provider and uid
#
flash.notice = "Signed in via your #{auth['provider']} account!"
sign_in_and_redirect(:user, authentication.user)
elsif user = create_new_omniauth_user(auth)
user.authentications.create!(:provider => auth['provider'], :uid => auth['uid'])
flash.notice = "Sucessfully created account!"
sign_in_and_redirect user #TODO: think about redirection
else
session["devise.user_attributes"] = auth
redirect_to new_user_registration_url
end
end
alias_method :facebook, :all
# def destroy
# @authentication = current_user.authentications.find(params[:id])
# @authentication.destroy
# flash.notice = "Successfully destroyed authenication!"
# redirect_to root
# end
def create_new_omniauth_user(auth)
user = User.new_with_session(auth, session)
if user.save
user
else
nil
end
end
end
In routes.rb I changed the controllers: {omniauth_callbacks: "omnitauth_callback"} to
controllers: {omniauth_callbacks: "authentication"}