Minimize validation headache for users in Rails App

okoth kongo
2 min readMay 23, 2020

I was creating a simple user model on a rails app. Well, the application was not that complicated so I expected I quick finish but got into trouble when I started noticing something strange about error messages when I ran the test and I wrote some ugly code later I found one-liner solution allow_blank: true. So here we are.

The user attributes specs were as follows:

  • user must have the user name and password
  • user name must be alphabetical characters of length 30 characters at most
  • password should be at least 8 characters, must have at least an upper case and lower case alphabetical character, a numeric character and a special character.

Let us put our focus on the password a bit since the same concept applies to the name

The user model would look like so:

class User < ApplicationRecordPASSWORD_REGEX = /\A (?=.{8,}) (?=.*\d) (?=.*[a-z]) (?=.*[A-Z])(? =.*[[:^alnum:]])/x 
validates :password, presence: true, format: { with: PASSWORD_REGEX, message: 'too weak'}
#user_name validations
end

A simple user model unit test

require 'rails_helper'
RSpec.describe User do
describe 'user attributes validations' do
# some more test
it 'does not save user with blank' do
user = Factory.build(:user, password: '')
user.save
expect(user.errors.messages[:password]).to eq(["can't be blank"])
end
# other more test
endend

If you run the above test it fails expected ["can't be blank] got ["can't be blank", 'too weak' but the password is blank 😕? your user may ask if they get such an error message, well that’s true. But password has more than one error messages since validations checks for both the format and the presence of password. This would be gladly present to our user in view. Imagine a user has not entered any password getting two error messages. password can’t be blank and password too weak. This is a little confusing right.

Well, so what do you to bypass this. That where our one-liner allow_bank: true comes in

class User < ApplicationRecordPASSWORD_REGEX = /\A (?=.{8,}) (?=.*\d) (?=.*[a-z]) (?=.*[A-Z])(? =.*[[:^alnum:]])/x 
validates :password, presence: true, format: { with: PASSWORD_REGEX, message: 'too weak', allow_blank: true}
end

If you rerun the test if now passes. With that simple modification, we have saved our users from headache of error messages which are not clearly understood. Gone on make those UIs user friendly ☺️. Happy hacking

--

--