Wherever possible, validate at the database level as well as at the model level.
Why? For starters, active record does not enforce validation in all contexts. The following methods skip validations, and will save the object to the database regardless of its validity:
decrement!
decrement_counter
increment!
increment_counter
toggle!
touch
update_all
update_attribute
update_column
update_counters
If you pass :validate => false
to save
, it will also skip validation. See the Active Record Validations and Callbacks Guide section on Skipping Validations for details. (If this worries you, there is even a gem for disabling these methods.)
So reason #1 is that Rails validations are not full-proof by any means: relying on them exclusively is risky, particularly for mission-critical validations such as uniqueness.
Speaking of which, reason #2 (off the top of my head): activerecord validations are prone to race conditions, and Rails' uniqueness validator in particular cannot guarantee uniqueness. Here's one article among many that documents why this is so.
Although they may be a rare occurrence, violations of uniqueness constraints can corrupt an entire data set. In the rare case that Rails is about to do this, you want at all costs to stop it, which is where the DB uniqueness constraint comes in: databases are built to handle this situation and will enforce uniqueness consistently, even when Rails does not.
And reason #3: why not validate both in the model and in the DB? Sure, you duplicate a bit, but that's generally a pretty minor concern compared with the payoff if Rails misses something like a uniqueness validation check. This is really not an either/or proposition: it's always better to duplicate validation in the DB wherever you can, particularly for mission-critical constraints such as uniqueness.
Anyway, those are my thoughts, hope that helps.
Ref: Where Correctness Is Enforced (screencast by Gary Bernhardt, need subscription to view)