Password validation and has_secure_password
railsUPDATE 2012-11-29: Actually, it appears this will be a moot point in Rails 4.
If the authentication needs of your Rails application are simple enough, third-party authentication libraries like Devise, Authlogic or Clearance can introduce considerable, unneeded overhead. Don’t get me wrong. All three libraries are well-written, well-maintained and popular enough that most support is little more than a Google search away. Nevertheless, if your needs are simple, you may find that Rails’ SecurePassword does everything you need with a minimum of fuss.
One of the handy things has_secure_password
does for you
is establish minimal validation rules for your password — the password
must be confirmed (by providing password
and
password_confirmation
attributes) and the
password_digest
attribute must not be blank. These
validation rules are the absolute minimum you need to ensure users
aren’t created with blank passwords, but you will almost certainly need
to augment them to provide a secure, user-friendly experience for your
application.
For starters, left as is, if you leave password
and
password_confirmation
blank, while validation will fail,
the validation errors might not be where you expect them.
[1] pry(main)> user = User.new(password: nil, password_confirmation: nil)
=> #<User id: nil, username: nil, email: nil, name: nil, password_digest: nil, created_at: nil, updated_at: nil>
[2] pry(main)> user.valid?
=> false
[3] pry(main)> user.invalid?(:password)
=> true
[4] pry(main)> user.errors[:password]
=> []
[5] pry(main)> user.errors[:password_confirmation]
=> []
[6] pry(main)> user.errors[:password_digest]
=> ["can't be blank"]
The password is indeed invalid, but the error message “can’t be blank”
is attached to the password_digest
attribute. The digest
is the encrypted hash in which the password is stored. It’s contents are
never meant to be presented to the user. Only the password
and password_confirmation
virtual attributes matter. You
probably don’t want to tell the user the password digest can’t be blank,
but rather the password itself can’t be blank. When displaying error
messages you will have to jump through extra hoops to ensure that the
relevant error message is displayed meaningfully.
Of course, you will most likely want to add some additional validations to your password field anyway if you intend to do any password vetting. While you’re at it, why not ensure the password isn’t blank?
class User < ActiveRecord::Base
has_secure_password
validates :password,
presence: { on: :create },
length: { minimum: 8, allow_blank: true }
end
Now if a user is created with a blank password, validation will fail and
the “can’t be blank” error will show up on the password
attribute itself. The password will also have a minimum length. Throw in
some validates_format_of
goodness if you must oblige
users to use more than one chracter class in their password (upper-case,
digits, punctuation). (Of course, obscure gibberish isn’t all it’s
cracked up to be)