Skip to content

Instantly share code, notes, and snippets.

@troelskn
Last active November 13, 2017 11:06
Show Gist options
  • Save troelskn/6240837 to your computer and use it in GitHub Desktop.
Save troelskn/6240837 to your computer and use it in GitHub Desktop.
Extend http://railscasts.com/episodes/235-devise-and-omniauth-revised to support scenario where a user first creates account without Facebook login, then later authenticates with Facebook.
# app/controllers/omniauth_callbacks_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
user = User.from_omniauth(request.env["omniauth.auth"])
if user.has_password? && user.facebook_uid_was.nil? && user != current_user
session["omniauth.user_attributes"] = user.attributes
redirect_to user_omniauth_link_url
elsif user.save
flash.notice = "You have been signed in"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to new_user_registration_url
end
end
# GET /users/auth/link
def link_user
load_user_from_session
render 'devise/omniauth/link_user'
end
# PUT /users/auth/link
def create_link_user
load_user_from_session
if @user.valid_password?(params[:user][:password])
@user.update_attributes(session["omniauth.user_attributes"])
@user.save!
session["omniauth.user_attributes"] = nil
flash.notice = "Signed in!"
sign_in_and_redirect @user
else
@user.errors[:base] << "Password invalid"
render 'devise/omniauth/link_user'
end
end
private
def load_user_from_session
email = session["omniauth.user_attributes"]["email"]
@user = User.where(:email => email).first
raise AbstractController::RecordNotFound unless @user
end
end
# config/routes.rb
# ...
devise_for :users,
path_names: { sign_in: "login", sign_out: "logout" },
controllers: { registrations: 'registrations', omniauth_callbacks: 'omniauth_callbacks' }
devise_scope :user do
get "/users/auth/link" => "omniauth_callbacks#link_user", :as => :user_omniauth_link
put "/users/auth/link" => "omniauth_callbacks#create_link_user"
end
# ...
# app/models/user.rb
class User < ActiveRecord::Base
class InvalidPassword < Exception ; end
def self.from_omniauth(omniauth)
user = where(:provider => omniauth.provider, :uid => omniauth.uid).first || where(:email => omniauth.info.email).first || new
user.uid = omniauth.uid
user.provider = omniauth.provider
user.email = omniauth.info.email if user.email.blank?
user.oauth_token = omniauth.credentials.token
user.oauth_expires_at = Time.at(omniauth.credentials.expires_at)
user
end
def has_password?
! encrypted_password.blank?
end
# ...
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment