Search code examples
ruby-on-railsruby-on-rails-3ruby-on-rails-3.1ruby-on-rails-3.2ruby-on-rails-2

How to update attribute that is being validate for uniqueness


Table 'leave_policies' has year, increment and total_entitled fields.

I have written 'validates_uniqueness_of :year' in LeavePolicy model.

update_attributes not working even I am not updating year field.

Please guide for mistake or suggest any better solution.

Class LeavePolicy
  validates_uniqueness_of :year
end

@leave_policy is object of LeavePolicy

In table a row with :id = 1 ,year = 1 , increment= 2 , total_entitled = 3. If I update row with id : 1 like

@leave_policy.update_attributes(:total_entitled => 5)

I got the error "year is already taken".


Solution

  • You are sure there is no other row with year of 1, and that the @leave_policy is actually an instance of the row with id 1?

    If it were actually a new record, it would fail this way, or if there were any other record with :year == 1.

    Validations are run on all attributes, even if you use update_attributes only on some, so if the year is not unique, it will fail even if you are only updating the increment or total_entitled fields.

    In general, validates_uniqueness is not a great answer on its own, as race conditions from checking in ruby can prevent it from enforcing uniqueness, so I would also use it with a unique key in the database.

    If you want to be able to skip the unique year validation when changing the other fields, you can set the attributes on the model, then call

    leave_policy.save(:validate => false) #for rails 3
    leave_policy.save(false) #for rails 2
    

    and that will skip all validations, but man, I would think twice. That seems to defeat the purpose, so I would instead pursue why it is that rails thinks you do not have a unique year - perhaps a look in your db will show there really is a dupe row for the year == 1.