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:
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:

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

And this is the facebook_user method:

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

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 and read about OmniAuth with devise. Episodes
#235, and #236 I would totally recommend you subscribe to his site,
by the way.


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.


I haven't tried it but would go for this:

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?


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?**