How to disable has_secure_password validation when a condition is true?

I have a User model that can save two types of users:

  1. Password-protected users (for this I need has_secure_password)
  2. Facebook users (for this I don’t need has_secure_password, but two different fields: provider and uid) So, when a normal user registers, the model should validate password fields with has_secure_password and validate the presence of the password field:
has_secure_password
validates :password, presence: true

This works. I have no problem with this.

But when a user wants to register through Facebook, the password is not needed, because provider and uid will be filled instead. The problem is that I don’t know how to disable has_secure_password in this case. I have tried this:

has_secure_password
validates :password, presence: true, unless: :facebook_user?

And this is the facebook_user method:

def facebook_user?
  provider != nil && uid != nil
end

But it doesn’t work, as it is still complaining about password_digest:

@messages={:password_digest=>["can't be blank"]}

What am I doing wrong? Isn’t it possible to disable has_secure_password selectively?

Go to RailsCasts.com and read about OmniAuth with devise. Episodes #235, and #236 I would totally recommend you subscribe to his site, by the way.

SC

Yes, I already watched those screencasts, but I still don’t know how to do it.

Did you ever get a solution to this? My app also allows authentication outside without the password.

Hi,

I haven't tried it but would go for this: http://guides.rubyonrails.org/active_record_validations_callbacks.html#conditional-validation

You probably didn't used right conditions. To figure it out I always use Rails console. Create 2 users, a FB and a nonFB and try them out.

This does not work with has_secure_password because this module automatically adds this validation: validates_presence_of :password_digest

so no matter how you change the condition of validation in your own model it just doesnt work. The solution I can think of is to write your own has_secure_password module, you can copy a lot code from the original from rails. Or use devise instead.

I also have dual login types (ldap and manual, the latter using has_secure_password) and had the same problem.

It might seem like a hack but the simple solution was to just set a bogus password for the ldap users (in the create method in my controller). I don't see any security problem with this since the ldap users cannot login manually using that password.

The solution is as follows:

remove has_secure_password and use traditional method

validates_confirmation_of :password, :unless => :facebook_user?

validates_presence_of :password_digest, :unless => :facebook_user?

def facebook_user?

not uid.nil? and not provider.nil?

end

Sorry, missed some details. The complete solution follows

** has_secure_password(validations: false) **


** validates_confirmation_of :password, :if => :password_present?**

** validates_presence_of :password, :on => :create, :unless => :facebook_user?**