karaschee
9/23/2012 - 7:07 AM

Multiple omniauth providers and omniauth-identity on the main user model

Multiple omniauth providers and omniauth-identity on the main user model

class UsersController < ApplicationController
  def new
    @user = env['omniauth.identity'] ||= User.new
  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 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
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
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
<%= 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 %>
# == 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
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