Skip to content

Instantly share code, notes, and snippets.

@stefanobernardi
Created September 23, 2012 07:07
Show Gist options
  • Save stefanobernardi/3769177 to your computer and use it in GitHub Desktop.
Save stefanobernardi/3769177 to your computer and use it in GitHub Desktop.
Multiple omniauth providers and omniauth-identity on the main user model
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def current_user
@current_user ||= User.find_by_id(session[:user_id])
end
def signed_in?
!!current_user
end
helper_method :current_user, :signed_in?
def current_user=(user)
@current_user = user
session[:user_id] = user.nil? ? user : user.id
end
end
# == Schema Information
#
# Table name: authentications
#
# id :integer not null, primary key
# user_id :integer
# provider :string(255)
# uid :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
class Authentication < ActiveRecord::Base
attr_accessible :provider, :uid, :user_id
belongs_to :user
def self.find_with_omniauth(auth)
find_by_provider_and_uid(auth['provider'], auth['uid'])
end
def self.create_with_omniauth(auth)
create(uid: auth['uid'], provider: auth['provider']) # and other data you might want from the auth hash
end
end
<%= simple_form_for @user, :url => '/auth/identity/register' do |f| %>
<%= @user.inspect %>
<h1>Create an Account</h1>
<%# specify :input_html to avoid params nesting %>
<%= f.input :name, :input_html => {:name => 'name'} %>
<%= f.input :email, :input_html => {:name => 'email'} %>
<%= f.input :password, :as => 'password', :input_html => {:name => 'password'} %>
<%= f.input :password_confirmation, :label => "Confirm Password", :as => 'password', :input_html => {:name => 'password_confirmation'} %>
<button type='submit'>Sign Up</button>
<% end %>
Rails.application.config.middleware.use OmniAuth::Builder do
provider :identity, fields: [:email, :name], model: User, on_failed_registration: lambda { |env|
UsersController.action(:new).call(env)
}
provider :abc
provider :def
end
AppName::Application.routes.draw do
match '/auth/:provider/callback', to: 'sessions#create' #omniauth route
match '/signup', to: 'users#new'
match '/login', to: 'sessions#new'
match '/logout', to: 'sessions#destroy'
resources :users #needed by omniauth-identity
end
class SessionsController < ApplicationController
def new
# Stuff to display on the login-page.
end
def create
auth = request.env['omniauth.auth']
# Find an authentication or create an authentication
@authentication = Authentication.find_with_omniauth(auth)
if @authentication.nil?
# If no authentication was found, create a brand new one here
@authentication = Authentication.create_with_omniauth(auth)
end
if signed_in?
if @authentication.user == current_user
# User is signed in so they are trying to link an authentication with their
# account. But we found the authentication and the user associated with it
# is the current user. So the authentication is already associated with
# this user. So let's display an error message.
redirect_to root_path, notice: "You have already linked this account"
else
# The authentication is not associated with the current_user so lets
# associate the authentication
@authentication.user = current_user
@authentication.save
redirect_to root_path, notice: "Account successfully authenticated"
end
else # no user is signed_in
if @authentication.user.present?
# The authentication we found had a user associated with it so let's
# just log them in here
self.current_user = @authentication.user
redirect_to root_path, notice: "Signed in!"
else
# The authentication has no user assigned and there is no user signed in
# Our decision here is to create a new account for the user
# But your app may do something different (eg. ask the user
# if he already signed up with some other service)
if @authentication.provider == 'identity'
u = User.find(@authentication.uid)
# If the provider is identity, then it means we already created a user
# So we just load it up
else
# otherwise we have to create a user with the auth hash
u = User.create_with_omniauth(auth)
# NOTE: we will handle the different types of data we get back
# from providers at the model level in create_with_omniauth
end
# We can now link the authentication with the user and log him in
u.authentications << @authentication
self.current_user = u
redirect_to root_path, notice: "Welcome to The app!"
end
end
end
def destroy
self.current_user = nil
redirect_to root_path, notice: "Signed out!"
end
def failure
redirect_to root_path, alert: "Authentication failed, please try again."
end
end
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# password_digest :string(255)
class User < OmniAuth::Identity::Models::ActiveRecord
attr_accessible :email, :name, :password, :password_confirmation
has_many :authentications
email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
def self.create_with_omniauth(auth)
# you should handle here different providers data
# eg. case auth['provider'] ..
create(name: auth['info']['name'])
# IMPORTANT: when you're creating a user from a strategy that
# is not identity, you need to set a password, otherwise it will fail
# I use: user.password = rand(36**10).to_s(36)
end
end
class UsersController < ApplicationController
def new
@user = env['omniauth.identity'] ||= User.new
end
end
@rutte
Copy link

rutte commented Nov 14, 2013

Looking good!

@robertwbradford
Copy link

Thanks for this and your article (http://bernardi.me/using-multiple-omniauth-providers-with-omniauth-identity-on-the-main-user-model/). I've been trying to piece it together with information from http://railscasts.com/episodes/235-devise-and-omniauth-revised?view=comments, but no success. Yet!

Do you know of any resources that show how to hook this all up with the devise gem? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment