Lugo Labs

Conditional validations with ActiveRecord

One of the processes that Ruby on Rails makes very easy is validating models conditionally. The perfect example I have encountered is validating parts of a model during updates, e.g. updating a user's password. We want to allow the users to enter the current password first, then enter a new password.

Let's write a failing test first:

ruby
# test/models/user_test.rb

class UserTest < ActiveSupport::TestCase
  test "current_password throws an error when entered incorrectly" do
    user = User.new(current_password_required: true, current_password: '')
    assert !user.valid?
    assert_equal ["Current password can't be blank"], user.errors.full_messages
  end
end

If we run the test now, in Rails 5 we can us the handy rails command, which makes running single tests much easier:

sh
bin/rails test test/models/user_test.rb

we get an ActiveModel::UnknownAttributeError exception about the unknown attributes, currentpasswordrequired, and current_password.

Let's add them to our User model:

ruby
class User < ActiveRecord::Base
  attr_accessor :current_password, :current_password_required
  validates :current_password, :presence => true, :if => :current_password_required
end

If we run the test now, we can see that it passes. Let's write the opposite test and see it pass:

ruby
# test/models/user_test.rb

test "current_password is ok when entered correctly" do
  assert user.valid?
end

We can then add other validations about checking that the password entered is the same as the current password, etc..

Happy coding!