The validation infrastructure within Rails is another one of the niceties that it provides. By decorating model classes with validation helpers you can quickly define a pretty thorough set of validations for a model. As an example of the types of validations that can be added to Rails models lets take a look at a user model created by the acts_as_authenticated Rails plugin.
class User < ActiveRecord::Base
# Virtual attribute for the unencrypted password
attr_accessor :password
validates_presence_of :login, :email
validates_presence_of :password, :if => :password_required?
validates_presence_of :password_confirmation, :if => :password_required?
validates_length_of :password, :within => 4..40, :if => :password_required?
validates_confirmation_of :password, :if => :password_required?
validates_length_of :login, :within => 3..40
validates_length_of :email, :within => 3..100
validates_uniqueness_of :login, :email, :case_sensitive => false
#other stuff
end
By using validates_presence_of, validates_length_of, validates_confirmation_of, and validates_uniqueness_of we're able to put together a detailed set of validation rules for our User model. Additionally, we can enable and disable certain validations by defining an :if parameter on our validations. With all these things in place Rails provides a nice default set of functionality for ensuring the validity of models. One of the things that's been on my mind since I started working with some of these validations is how they might scale, and how well they'd support a model object with complex validation rules. While it seems as though what's provided out of the box by Rails could be bent in order to meet most requirements I came across something today that looks very promising.
The
ActiveSpec project aims to provide domain driven design (DDD) style specificiations to the Ruby world. While Rails is getting all the attention, ActiveSharp isn't limiting itself to Rails, but instead makes itself available to all of Ruby. On my train ride home tonight I read through the Introduction to ActiveSpec and was pretty excited about the direction it's headed. It's pretty early in the game so the current bits may not be ready for prime time, however, that doesn't make them any less promising. In addition to providing the ability to create simple specifications, composite specifications, ActiveSpec also provides a base ActiveSpec class with macros to help make the process of creating complex specifications more straight-forward. I've included some sample code snippets below, but to
get a full run down of ActiveSpec checkout the Introduction.# Composite Specifications
spec = CompositeSpecification.new
spec.add_specification(SizeSpecification.new(6, :username))
spec.add_specification(CollectionSpecification.new(18..30, :age))
spec.add_specification(ConfirmationSpecification.new(:password))
spec.satisfied_by?(User.new)
# Custom Specification Class
class UserSpecification < ActiveSpec::Base
requires_presence_of :username, :password
requires_size 6, :password
requires_confirmation_of :password
requires_inclusion_in 18..30, :age
end
UserSpecification.satisfied_by?(some_user)
User.find_by_specification(SomeAdvancedUserSpecification)
User.find(:all, :conditions => SomeAdvancedUserSpecification.to_sql)