Rails - принудительное заполнение поля в верхнем регистре и однозначное подтверждение

Аэропорты имеют четырехбуквенные коды ИКАО. По соглашению, они всегда имеют верхний регистр. Я создаю форму для ввода пользовательского ввода, но эта форма должна быть способна принимать пользовательский ввод в смешанном случае и препятствовать им создавать обманки.

По умолчанию :uniqueness зависит от регистра, конечно. Я понял, как преобразовать пользовательский ввод в верхний регистр, прежде чем он будет сохранен, но проблема в том, что это скорее пост-валидация, а не предварительная проверка.

Например, если уже есть аэропорт с ИКАО KLAX, пользователь может ввести KLAX, он будет проверен как уникальный, а затем преобразован в верхний регистр и сохранен, что приведет к дублированию.

Вот мой код модели в настоящее время.

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

Ответ 1

Просто исправлено (как и многие проблемы с Rails), как указал Дэнни выше, хотя и не в своем собственном ответе, поэтому я не могу его принять:), изменение before_save до before_validation прекрасно исправляет его.

Ответ 2

Или немного другое: запишите setter для icao, который преобразует все, что было в него, в верхний регистр:

def icao=(val)
    self[:icao] = val.upcase
end

И тогда вы можете использовать регулярную проверку уникальности (создать резервную копию с уникальным индексом в вашей базе данных). Может даже немного облегчить работу БД во время находок, потому что больше не нужно беспокоиться о безразличных сравнениях.

Надеюсь, это поможет!

Ответ 3

попробуйте следующее:

validates :icao, :uniqueness => { :case_sensitive => false }

Ответ 4

Обновлен ответ для 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