skip to Main Content

I have successfully implemented oAuth with omniauth-facebook and omniauth-google but I am having difficulties with implementing omniauth-twitter as it does not provide an email address.

I searched through available solutions on the Internet and one solution pointed out at removing Devise’s email validation but email validation is needed for my app.

What I want instead is to redirect the user to a new form where the user only has to enter a new email address to complete his oAuth registration but I am not sure how to link it with the oAuth data to complete the registration as I am getting errors when I submit the form since username and password can’t be blank from devise while only email is displayed in that form.

CallbackController

    def twitter
        @user = User.from_omniauth(request.env["omniauth.auth"])
        if @user.persisted?
          flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Twitter"
          sign_in_and_redirect @user, :event => :authentication
        else
          session["devise.twitter_data"] = request.env["omniauth.auth"].except("extra")
          redirect_to twitter_register_path 
        end
    end

twitter_register_path contains the view where the user has to fill in his email address to complete registration.

User Model

def self.from_twitter_omniauth(auth,email)
   where(provider: auth["provider"], uid: auth["uid"]).first_or_create do |user|
      user.provider = auth["provider"]
      user.uid = auth["uid"]
      user.email = email
      user.name = auth["info"]["name"]
      user.password = Devise.friendly_token[0,20]
      user.remote_poster_image_url = auth["info"]["image"].gsub('http://','https://')
    end
end

Twitter signup form (twitter_register_path)

<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= f.error_notification %>

  <div class="form-inputs">
    <%= f.input :email, required: true,label: false %>
  </div>

  <div class="signup">
    <%= f.button :submit, "Sign up",:class =>"register-button" %>
  </div>
<% end %>

Even though the Twitter API recently allows applications to request additional permissions for their email, I am unsure of how to implement that.

2

Answers


  1. Chosen as BEST ANSWER

    I finally managed to solve it this way.

    After the user is redirected and if it's a new user, we will render a form TwitterForm for the user to input an email to complete the registration.

    Next, the form will be submitted to a custom action that we specified, in my case I put it under UsersController that'll complete the sign up process using the Twitter session data and the email that the user inputted.

    You can't put the action together inside the CallbacksController due to some issues with Devise which I am unsure as to why there's an error.

    Devise CallbacksController

     def twitter
            auth = request.env["omniauth.auth"]
            @user = User.where(provider: auth.provider, uid: auth.uid).first_or_create
            if @user.persisted?
                flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Twitter"
                sign_in_and_redirect @user, :event => :authentication
            else
                @form = TwitterForm.new 
                session["devise.twitter_data"] = request.env["omniauth.auth"].except("extra")
                render :layout => 'none'
            end
        end
    

    UsersController

    def twitter_register
        @form = TwitterForm.new(params[:twitter_form])
        if @form.valid?
          email = params[:twitter_form][:email]      
          @user = User.from_twitter_omniauth(session["devise.twitter_data"],email)
          if @user.persisted?
            flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Twitter"
            sign_in_and_redirect @user, :event => :authentication
          else
            redirect_to register_path 
          end
        else 
          render 'callbacks/twitter',layout: 'none'
        end
      end
    

    TwitterForm

    class TwitterForm
      include ActiveModel::Model
      attr_accessor :email
      validates :email, presence: true,:format => { :with => /A([^@s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})Z/ }
    end
    

    User Model

    def self.from_twitter_omniauth(auth,email)
       where(provider: auth["provider"], uid: auth["uid"]).first_or_create do |user|
          user.provider = auth["provider"]
          user.uid = auth["uid"]
          user.email = email
          user.name = auth["info"]["name"]
          user.password = Devise.friendly_token[0,20]
          user.remote_poster_image_url = auth["info"]["image"]
        end
    end
    

Please signup or login to give your own answer.
Back To Top
Search