15

Possible Duplicate:
Ruby on Rails: Is it better to validate in the model or the database?

I see that it's possible to add same constraint/validation in both Rails model and migration. But which one is the best approach? Is it a good practice to validate both at model and database level (and why)? or they same in rails?

For e.g. We can do same validation for name in both model and migration

class User < ActiveRecord::Base
  validates :name, :uniqueness => true, :presence => true
end

class CreateUser < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name, :unique => true, :null => false
    end
  end
end
Community
  • 1
  • 1
18bytes
  • 5,951
  • 7
  • 42
  • 69
  • Good question. I would say do it in the model and let it enforce it to the database, but I'd be interested in hearing what others have to say. – port5432 Oct 29 '12 at 13:53

1 Answers1

29

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)

Chris Salzberg
  • 27,099
  • 4
  • 75
  • 82
  • 1
    Excellent answer, far better than the ones in exact duplicate question. – 18bytes Oct 29 '12 at 14:22
  • 9
    reason #4: a DB has entity on its own, it can be used outside the Rails app. – tokland Oct 29 '12 at 14:29
  • @Sundar Thanks! Yeah those other answers were not terribly insightful... – Chris Salzberg Oct 29 '12 at 14:30
  • @tokland Thanks, that's very true. I'm sure there are many more as well. – Chris Salzberg Oct 29 '12 at 14:31
  • 1
    Nice answer! However, all your reasons show that it is better to validate at the database level. It still doesn't convince me that it is better to have validations at both levels. Any reason why do you need to validate at the model level as well? Wouldn't it be enough to have the validation on the database? – Yahya Oct 04 '15 at 08:04
  • 1
    @YahyaPoonawala Without a rails validator you will just get an exception at the db level every time you try to save something invalid, which is obviously not ideal. Just as one example, validation errors on form input wouldn't work. – Chris Salzberg Oct 25 '15 at 00:57