1

I have the following action:

users.rb:

  def omniauth_create
    auth = request.env["omniauth.auth"]
    user = User.from_omniauth(env["omniauth.auth"])
    unless user.email.blank?
      if user.id.nil?
        # Save the user since he hasn't been created yet
        user.save!
      end
      sign_in user
      redirect_back_or user
    else
      # Send user to a form to fill his email
      #session[:omniauth] = request.env['omniauth.auth'].except('extra')
      redirect_to(enter_email_path(oprovider: user.provider,
                                   ouid: user.uid,
                                   oname: user.name,
                                   opassword: user.password,
                                   opassword_confirmation: user.password))
    end
  end

It does the following:

  • If the user's email is not blank, sign him in, and redirect him to his profile (and save him if his id is nil. In other words, if he hasn't been created yet).
  • If the user's email is blank, send him to enter_email_path (where the user can enter his email).

Now I want to add another if statement that flashes an error if the email had been already taken, and redirects the user to the root_path

I'm not very sure how to do this, Any suggestions? (and where to put that if statement?)

EDIT:

Strange, got this instead of the redirect to the root path:

Validation failed: Email has already been taken

I don't know if this helps but here is the origin of from_omniauth:

  def self.from_omniauth(auth)
    find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
  end

  def self.create_with_omniauth(auth)
    new do |user|
      user.provider = auth["provider"]
      user.uid = auth["uid"]
      user.name = auth["info"]["name"]
      user.email = auth["info"]["email"]
      user.password = user.password_confirmation = SecureRandom.urlsafe_base64(n=6) 
    end
  end

The code as it is right now:

user.rb:

# if user.email.present?
  if user.id.nil?
    # User.find_by_email(user.email).present?
    if User.exists?(:email => user.email)
      redirect_to root_path
    end
    user.save!
  end
  sign_in user
  redirect_back_or user
else

(the rest didn't change).

It seems like the code is ignoring the if User.exists?(:email => user.email) part?

alexchenco
  • 53,565
  • 76
  • 241
  • 413

3 Answers3

4

Rails has a method to check if an object exists based on parameters. You could do this:

if user.email.present?
  if user.id.nil?
    if User.exists?(:email => user.email)
      # return redirect email is already token
    end

    # save user
  end
  # sign_in user
else
  # redirect to get email
end

By the way, I am not familiar with Omniauth so I am not sure what is right but new_record? is usually used when checking if object is already saved or not. If you have an id, it usually is.
If you are confused you could create functions in your User model for better reading like

class User
  def new?
    id.nil?
  end

  def email_taken?
    self.class.exists?(:email => email)
  end
end

# back to controller
if user.email.present?
  if user.new?
    if user.email_taken?
      # return redirect email is already token
    end

    # save user
  end
  # sign_in user
else
  # redirect to get email
end
oldergod
  • 15,033
  • 7
  • 62
  • 88
  • Thanks a lot! But I'm getting `Validation failed: Email has already been taken` (please see my **EDIT**). – alexchenco Nov 06 '12 at 05:36
  • @alexchenco I did not write `return` after `email_taken?` by random. You want to go out of the function, don't want to save this user. So you should use `return redirect_to root_path` here. – oldergod Nov 06 '12 at 05:45
  • @redirect_back_or user Oh sorry, didn't see that. I forgot what `return` did in Ruby. Thanks! By the way, why return wasn't necessary in `redirect_back_or user`? – alexchenco Nov 06 '12 at 06:05
  • @alexchenco because that is the end of the function and no other code will be executed after this. You could add it if you want but that would not change anything. In ruby, the last statement executed of a function is returned automatically. – oldergod Nov 06 '12 at 06:08
  • Oh, I see, I was looking the "end" as the end of `if`. Didn't consider the `else` as an "end". Thanks again! – alexchenco Nov 06 '12 at 06:10
1

try this

 def omniauth_create
    auth = request.env["omniauth.auth"]
    user = User.from_omniauth(env["omniauth.auth"])
    if user.email.present?
      if user.id.nil?
        if User.find_by_email(user.email).present?
          # send error email already be taken
          # or login with that user that means define that user for sign in
        else
          # save user and login with that user
          user.save!  
        end
        sign_in user
        redirect_back_or user
      end 
    else
      # Send user to a form to fill his email
      # session[:omniauth] = request.env['omniauth.auth'].except('extra')
      redirect_to(enter_email_path(oprovider: user.provider,
                                   ouid: user.uid,
                                   oname: user.name,
                                   opassword: user.password,
                                   opassword_confirmation: user.password))

    end

Update

you can also use find_or_create method

def self.find_or_create(attributes)
  Model.where(attributes).first || Model.create(attributes)
end

Update 2

In your Modal file

  class << self
    def create_with_omniauth(auth)
      create! do |user|
        user.provider = auth['provider']
        user.uid = auth['uid']
        if auth['info']
          user.uid = auth['uid'] || ""
          user.name = auth['info']['name'] || ""
          user.email = auth['info']['email'] || ""
          user.access_token = auth['credentials']['token'] || ""
          user.oauth_token_secret = auth['credentials']['secret'] || ""
          user.oauth_token = auth['credentials']['token'] || ""
        end
      end
    end
  end

In your controller

  def create
    auth = request.env["omniauth.auth"]
    user = User.where(:provider => auth['provider'],:uid => auth['uid']).first || User.create_with_omniauth(auth)
    session[:user_id] = user.id
    redirect_to root_url 
  end
Community
  • 1
  • 1
Dipak Panchal
  • 5,996
  • 4
  • 32
  • 68
  • Thanks! But got this: `Validation failed: Email has already been taken (please see my EDIT).` – alexchenco Nov 06 '12 at 05:40
  • Thanks! But I'm confuse, did you mean to put it in my `create` action or `omniauth_create` action? EDIT: But if email and password are empty, then I will get an error? – alexchenco Nov 06 '12 at 05:51
  • Yeah, I got this: `Validation failed: Email can't be blank, Email is invalid, Password confirmation can't be blank:` – alexchenco Nov 06 '12 at 06:01
0

Not sure if you want a rails answer or a SQL answer, but you could use the following SQL to find your response:

select id from users where email = :email 

If this returns 0 rows, the email does not exist, if it returns 1, it does exist. I guess you could also use

Users#find(:first, :conditions => 'email = #{email}') 

but I haven't tested this.

hd1
  • 33,938
  • 5
  • 80
  • 91