I was able to allow users to sign-in with either their username or email by implementing this bit of code in my model concerns.
module ClassMethods
def authenticate(username, email, password)
user = User.find_by(username: username)
user_email = User.find_by(email: email)
return unless user || user_email
if user
user.send :new_token
user.authenticate password
elsif user_email
user_email.send :new_token
user_email.authenticate password
end
end
end
included do
has_secure_password
before_create :set_token
after_find :fix_up_token
validates :email, uniqueness: true
validates :email, presence: true
validates :username, uniqueness: true
validates :username, presence: true
validates :password_confirmation, presence: true, on: :create
end
I originally was trying to create a conditional for 'user' with the find_by method but I didn't have any luck. I ended up with the idea of creating 'user_email' as a work around and it works, but I feel like there has to be a way to do this with one variable.
Update
I was able to get it working with two of the answers below.
This one here from max:
def authenticate(username, email, password)
user = User.where(email: email)
.or(User.where(username: username)).take
return unless user
user.send :new_token
user.authenticate password
end
And this one here from Sajjad Umar:
def authenticate(username, email, password)
user = User.find_by(username: username) || User.find_by(email: email)
return if user.blank?
user.send :new_token
user.authenticate password
end
Update 2
Sean recommended using a regex to scan the input for email format. I have the requirement for email format covered already, but I did want to make sure that a user can not create a username that matches an email of a different user. So, I placed format validations on the username using regex.
included do
has_secure_password
before_create :set_token
after_find :fix_up_token
validates :email, uniqueness: true
validates :email, presence: true
validates :username, uniqueness: true
validates :username, presence: true
validates :username, format: { with: /\A[a-zA-Z0-9]+\z/,
message: 'only allows letters and numbers' }
validates :password_confirmation, presence: true, on: :create
end
Thanks to everyone for helping me out!