I'm porting a project from Rails 3 to 3.1. My authentication system was easily switched over to the new has_secure_password in ActiveRecord. The only problem I'm running into is that I also use OmniAuth and I have the system set up so if a user signs up using one of the OmniAuth providers the account shouldn't require a password. I can't seem to override the password_digest validations setup by has_secure_password. Is there anyway to turn off those validations and write my own, or am I going to have to just use my old hand written bcrypt functions from my Rails 3 version of the site?
I ended up going back to using custom methods. However, I did realize afterwards that I should've been able to use a before_validation callback to check the conditions, then if they matched set the password_digest to anything simple like '0'. This way the digest would never be blank, but at the same time it shouldn't ever validate as a correct password, making them sign in through OmniAuth.
Feel free to correct me if I'm mistaken.
Scott, your idea is correct. I've been wrestling with this problem to no avail. I tried to override 'has_secure_password' and it simply won't work. No matter where I stuck the code.
Instead I have the following:
class User < ActiveRecord::Base
has_secure_password
validates_presence_of :password, :on => :create, :if => :password_required
# Associations
has_many :authentications
# Callbacks
before_validation :no_password_omniauth
# Gets set to true if the caller is trying to authenticate with omniauth.
@called_omniauth = false
# Build new omniauth users
def apply_omniauth(omniauth)
authentications.build(
:provider => omniauth['provider'],
:uid => omniauth['uid'])
self.first_name = omniauth['user_info']['first_name'] if self.first_name.blank?
self.last_name = omniauth['user_info']['last_name'] if self.last_name.blank?
self.email = omniauth['user_info']['email'] if omniauth['user_info']['email'] && self.email.blank?
@called_omniauth = true
end
def password_required
return false if @called_omniauth == true
(authentications.empty? || !password.blank?)
end
private
def no_password_omniauth
self.password_digest = 0 unless password_required
end
end
The apply_omniauth method gets called from the controller when someone is trying to authenticate or sign up.
Thanks for the idea you nailed it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With