Validation 101

Data validation is crucial to web applications–especially e-commerce applications, where money is involved. Bad data can destroy the usefulness of (or even shut down) an application! What’s more, validation needs to be centralized–you want to keep your validation in one place, and not have to cut-and-paste code.

Rails provides a simple solution for both of these problems in a single sweep–it allows you to specify validation at the model-level. Model-level validation means no instance of the model gets saved to the database, except that it passes validation; and validation sits in one place, so you can easily view it–no duplicate code necessary!

Rails provides two useful tools for validation; the first being a set of validates_ methods, for basic validation, and a validate function which, if used with errors.add, forces the application not to save data if it fails validation.

Examples always add clarity, so let’s imagine we’re creating an online jewelry store. Each jewelry product has a title, a description, a price, and a quantity (how many we have in stock). First, let’s add validation to make sure the store administrator can’t forget to enter any of these fields. Open up the model for product:


class Product < ActiveRecord::Base
validates_presence_of :title, :description, :price, :quantity
end

There, one line is all it takes; if you use the scaffold method, and try to save a book without all the data, Rails will highlight the empty fields and emit a large error message.

But what if someone enters "ha ha!" as a price? How can we stop them? Simply validate that price and quantity are numbers:


validates_numericality_of :price, :quantity

Again, if we put in a non-numerical price, Rails will display an appropriate error message.

You can also ensure that your jewelry items are unique, with validates_uniqueness_of :title.

Finally, we want to ensure both price and quantity are positive. To do this, we simply add a custom validate method; Rails calls this automatically before it saves any fields, and doesn't save if a model fails validation.


def validate
if price.nil? || price < 0.01
errors.add(:price, "should be at least one cent")
end

if quantity.nil? || quantity < 1
errors.add(:quantity, "should be at least 1")
end
end

If the price is less then one cent, or the quantity is less then one, then validation fails. (We use less then one cent because the user can enter 0.001, which will pass "price <= 0" validation, but round down to 0.) Also, you'll notice the nil? checks; these ensure that our application doesn't crash if the user fails to specify a price or quantity.

Notice you can also add more complex validation; you can specify that you must have at least 10 of an item in stock, or that the product title begins with the letters A, B, or X, or any other arbitrary business rule. This allows us the power and flexibility to easily capture and model our business logic into Rails.

About Ashiq Alibhai

Ashiq Alibhai, PMP, has been a Rails aficionado since 2007, and developed web applications since early 2003, where he learned PHP in one summer. As the driving-force behind RailsRocket and the Launchpad project, he seeks to share the ease of development with Rails far and wide.
This entry was posted in Development and tagged , , , , . Bookmark the permalink.

One Response to Validation 101

  1. angel chen says:

    Why don’t you do price < 0.01.to_d instead so that it will compare using bigdecimal instead of float.