In general this looks pretty good.
- You allow '+' signs in email addresses
- You allow the email address to be mixed-case.
Here's a related question on doing validation of email addresses based on a regex.
The only thing that seems glaring to me is that it looks like you're storing the password in clear text instead of storing it encrypted and that you're not validating that the password confirmation matches the password.
Here are a couple lines from a project where we had pretty restrictive password rules. You may want to adapt them.
validates_presence_of :password, :if => :password_required?
validates_confirmation_of :password, :if => :password_required?, :message => "Your password and confirmation must match."
validates_format_of :password, :with => /^[\S]{4,}$/, :message => "Your password must be at least 4 characters and contain no spaces or tabs.", :if => :password_required?
def password_required?
self.new_record?
end
Putting password_required?
into its own method gives you more flexibility in specifying the circumstances where you want to do the validation.
Regarding storing the passwords encrypted, I've used SHA-1 hashes for this. Basically, you store the password's SHA-1 hash, then when they authenticate you compare the SHA-1 hash of the password they enter to the stored hash. That way the password's aren't saved in clear text. Here's a snippet:
# Encrypts some data with the salt.
def self.encrypt(password, salt)
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
end
# Encrypts the password with the user salt
def encrypt(password)
self.class.encrypt(password, salt)
end
These setup both of User.encrypt(password, salt)
and user.encrypt(password)
methods. Use the class-level method to generate an encrypted version of what someone types in at login, and use the object-level method when saving someone's password. I've left out some of the pieces, but at least this gives you something to think about.
Note: Here's more info on SHA-1 hashes than you'll ever need.