1

Does validates :uniqueness get called every time an object is saved even if a field has not changed? Isn't this a performance issue?

validates :name, :schedule_id, :uniqueness => true

It seems to be the case that it does. So isn't it almost always necessary to make sure a change has taken place before running the validation? As every field being checked for uniqueness requires a database hit.

This would be better:

validates :name, :schedule_id, :uniqueness => true, :if => "name_changed? || schedule_id_changed?"

And this much better, if a bit more verbose:

validates :name, :uniqueness => true, :if => :name_changed?
validates :schedule_id, :uniqueness => true, :if => schedule_id_changed?

Gist here: https://gist.github.com/4017019

John H
  • 2,488
  • 1
  • 21
  • 35
  • 2
    What exactly is your question? Are you just looking for confirmation that uniqueness validations are always run? – Peter Brown Nov 05 '12 at 12:54
  • Yeah. If the field hasn't changed I mean. And if so shouldn't there be a debate on whether the UniquenessValidator should inherently know when to run the validation. It's a pretty expensive, unnecessary request to run on the DB if the field hasn't changed anyways? – John H Nov 05 '12 at 13:00
  • The second one seems more agile and would help in preventing the unnecessary validations when the object has not changed but as far as the normal validations are concerned they have to be run everytime when you save your data in the DB this one small overhead will go a long way in ensuring that the data always remain valid and correct... – Aditya Kapoor Nov 05 '12 at 13:05
  • 1
    If you're really concerned about performance, you might want to use [unique indexes](http://stackoverflow.com/questions/1449459/how-to-make-column-unique-and-index-it-in-rails-migration) in your database. – Peter Brown Nov 05 '12 at 13:28
  • Thanks, we do use indexes of course but I think in this case it'd be quicker to stop the validation at the application layer since it's not necessary for it to hit the database at all – John H Nov 05 '12 at 13:55

1 Answers1

1

try this

   validates :name, :uniqueness => true, :if => lambda {self.name_changed? }
Aayush Khandelwal
  • 1,071
  • 7
  • 11
  • The lambda isn't really necessary though, the rails validation takes a conditional based on dirty attributes as I've shown in the example. I'm trying to get to the root of the problem, does the default behaviour observe changes to the fields or just get called with every save. – John H Nov 05 '12 at 12:53
  • 1
    The default behavior does not observe changes. That's what `:if` and `:unless` conditions are for. – deefour Nov 05 '12 at 12:56
  • 1
    How is this different than what the OP had at the end of the question? – Peter Brown Nov 05 '12 at 12:57
  • Which answers my question and is fair enough really. I don't mind using the conditionals but is there ever really a case where you'd want to validate the uniqueness of a field that hasn't changed? Maybe there's an argument that it'd be more DRY for the validator to check for this? – John H Nov 05 '12 at 13:18