Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 5, Devise, Omniauth, Twitter

I know this has been asked many times, but the answers are never fully acceptable to me.

So I am following Ryan Bates' Railscast about this topic, and mixing that with the official Devise Omniauth guide (that is based on FB), but I am just not getting it to work like I expect, so I would love some help.

I have a Users::OmniauthCallbacksController that looks like this:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def all
    @user = User.from_omniauth(request.env["omniauth.auth"])

    if @user.persisted?
      sign_in_and_redirect root_path, :event => :authentication #this will throw if @user is not activated
      set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
    else
      session["devise.twitter_data"] = request.env["omniauth.auth"].except("extra")
      flash[:notice] = flash[:notice].to_a.concat resource.errors.full_messages
      redirect_to new_user_registration_url
    end
  end

  alias_method :twitter, :all

  def failure
    redirect_to root_path
  end
end

Then I also have two methods on my User.rb

  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.update(
        email: auth.info.email,
        password: Devise.friendly_token[0,20],
        username: auth.info.nickname,
        remote_avatar_url: auth.info.image,
        token: auth.credentials.token,
        secret: auth.credentials.secret
      )
    end
  end

  def self.new_with_session(params, session)
    super.tap do |user|
      if data = session["devise.twitter_data"]
        # user.attributes = params
        user.update(
          email: params[:email],
          password: Devise.friendly_token[0,20],
          username: data["info"]["nickname"],
          remote_avatar_url: data["info"]["image"],
          token: data["credentials"]["token"],
          secret: data["credentials"]["secret"]
        )
      end
    end
  end

I run into a variety of problems. The most immediate is because I am setting the password, the user doesn't know the password when they try to login (and I don't auto sign them in upon confirmation).

But if I don't set the password, it doesn't ask them to set the password...so that's kinda weird too.

These are my devise settings on my User model:

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :confirmable, :omniauthable, :omniauth_providers => [:twitter]

  validates :username,
    presence: true,
    uniqueness: {
      case_sensitive: false
    }

  validate :validate_username

  def validate_username
    if User.where(email: username).exists?
      errors.add(:username, :invalid)
    end
  end

So my question is this, when someone signs up via Twitter, do they need to enter a password? I automatically send them to the registration/new.html.erb anyway because Twitter doesn't return an email value. But I am trying to just get the process working first, before optimizing it.

How do I deal with the password issue?

Edit 1

For more clarity, I will have to deal with this password_required issue regardless of the OAuth provider.

So how do I override that requirement for all OAuth providers?

like image 466
marcamillion Avatar asked Jul 01 '16 01:07

marcamillion


1 Answers

You should add the following method to the User class:

def password_required?
  (provider.blank? || uid.blank?) && super
end

Since Twitter doesn't return the user's email, you may also want to tweak that email validation, but redirecting the user to registration/new.html.erb like you are already doing seems like the correct approach to me.

like image 84
Ashitaka Avatar answered Nov 11 '22 13:11

Ashitaka