July 10, 2011

Rails Authlogic Conditional Validations

When building a web app, one of the first features you usually add is the ability for users to register and log in to see their data linked with their personal account. And most of the time, you will be using validations on your User model to ensure that the email is formatted like a real email address, and password is at least characters, and so on.

(Side note: If you don't know about validations, check them out at the official Rails guide - they're dead useful.)

In this post, I'll be referencing the authentication gem Authlogic and the fact that it automatically handles user model validations for you. If you're using another gem/plugin or building your own authentication system, you're probably interested in the ActiveRecord's validation documentation.

Gradual Engagement

Anyways, so now you have your validations in place. But what if you want to enable access for "guest" users, or allow users to omit information like emails or passwords under certain circumstances?

Coined "gradual engagement" by the Rails/Authlogic community, there's a simple way to do this. I spent a couple of frustrated hours this morning stuck on this problem and hunting through Google Groups logs, Github Gists and various blogs, so I'm happy to share. From Kevin Triplett's Github Gist, all you need to do is add certain config options to your acts_as_authentic line in your model.

In my case (in app/models/users.rb):

acts_as_authentic do |c|
  c.merge_validates_format_of_login_field_options :unless => :guest?
  c.merge_validates_length_of_login_field_options :unless => :guest?
  c.merge_validates_length_of_password_field_options :unless => :guest?
  c.merge_validates_format_of_email_field_options :unless => :guest?
end

Multiple validation groups

Alternatively, if you want to have finer grained control over what validations are enabled when and have multiple "validation groups" to turn on and off, I stumbled across another solution that might interest you: Put this code in your lib/ folder. In your model of interest, add these lines to configure your validation groups (courtesy of Alan Gutierrez from the Authlogic Google Group):

class User < ActiveRecord::Base
  validates_presence_of :first_name, last_name, :email
  validation_group :invitation, :fields => ["email"]
  validation_group :registration, :fields => ["first_name", "last_name"]
end

And:

@user.enable_valiation_group(:invitation)
@user.save! # Will only validate email.

Easy peasy.