Reputation: 1712
Airports have four-letter ICAO codes. By convention, these are always uppercase. I'm creating a form for receiving user input, but this form needs to be able to accept user input in mixed case, and prevent them from creating dupes.
The default :uniqueness
is case-sensitive, of course. I figured out how to transform the user's input to uppercase before it gets saved, but the problem is that this appears to be post-validation, instead of pre-validation.
For example, if there is already an Airport with ICAO of KLAX
, a user can enter klax
, it will get validated as unique, and then transformed to uppercase and stored, resulting in duplicates.
Here's my model code at present.
class Airport < ActiveRecord::Base
validates :icao, :name, :lat, :lon, :presence => true
validates :icao, :uniqueness => true
before_save :uppercase_icao
def uppercase_icao
icao.upcase!
end
end
Upvotes: 11
Views: 12181
Reputation: 3186
Updated answer for Rails 4.
class Airport < ActiveRecord::Base
validates :icao, :name, :lat, :lon, :presence => true
validates :icao, :uniqueness => { case_sensitive: false }
def icao=(val)
write_attribute :icao, val.upcase
end
end
Upvotes: 5
Reputation: 14619
Or a slightly different take: Write a setter for icao
that converts anything thrown at it to uppercase:
def icao=(val)
self[:icao] = val.upcase
end
And then you can use regular uniqueness validation (back it up with a unique index in your DB). Might even make things a little easier for the DB during finds, 'cause it doesn't have to worry about case-insensitive comparisons any more.
Hope this helps!
Upvotes: 12
Reputation: 1712
Simply fixed (as many problems with Rails are) - as Danny pointed out above, although not in his own answer so I can't accept it :), changing before_save
to before_validation
fixes it perfectly.
Upvotes: 2
Reputation: 7164
try this:
validates :icao, :uniqueness => { :case_sensitive => false }
Upvotes: 8