Когда у нас будет новый диапазон для одного поля в ActiveRecord, можем ли мы немедленно изменить код проверки? - PullRequest
0 голосов
/ 11 апреля 2020

Скажем, если у нас есть

class SomeData < ActiveRecord::Base
  validates :foo, inclusion: 33..99

и теперь, скажем, мы сузим диапазон до 66..99, но в базе данных есть много значений, которые все еще находятся между 33 и 65 Можем ли мы немедленно изменить вышеуказанный код на

class SomeData < ActiveRecord::Base
  validates :foo, inclusion: 66..99

? Это проблема, если данные просто считываются в систему? (даже в более ранней версии Rails, такой как 3.2?)

1 Ответ

2 голосов
/ 11 апреля 2020

Изменение проверки фактически не влияет напрямую на существующие данные в вашей базе данных. Проверки выполняются только тогда, когда в модель вызывается #valid?.

Это происходит неявно при вызове:

  • .create и .create!
  • #save и #save!
  • #update и #update!

И это приводит к тому, что эти методы блокируются так, что либо происходит откат, либо запрос db не запускается в первом place.

Можем ли мы немедленно изменить валидацию?

Да. Проверка действительно вступит в силу, только если вы попытаетесь обновить существующую запись. В этом случае ранее действительная запись теперь может быть недействительной. Это не разрешит обновление, если значение не будет обновлено до нового разрешенного диапазона.

Работа с устаревшими данными

Если вы хотите, чтобы пользователи все еще обновляли существующие записи с использованием недопустимых данных согласно новым правилам есть несколько хитростей.

Опции if: и unless:

class SomeData < ActiveRecord::Base
  validates :foo, inclusion: 33..99, if: :legacy_record?
  validates :foo, inclusion: 66..99, unless: :legacy_record?
end

Есть несколько способов реализовать :legacy_record?, например, в виде логического флага в базе данных. , Обратите внимание, что их не следует путать с ключевыми словами ruby. Это просто параметры sh.

пользовательские методы проверки:

class SomeData < ActiveRecord::Base
  validate :my_validation_method
  def my_validation_method
    rng = legacy_record? ? 33..99 : 66..99
    errors.add(:foo, "out of range") unless rng.cover?(foo)
  end
end

Наследование одной таблицы

class Thing < ActiveRecord::Base
  validates :foo, inclusion: 66..99
end

class LegacyThing < ActiveRecord::Base
  self.table_name = "things"
  validates :foo, inclusion: 33..99
end

В этом примере вы добавили бы things.type varchar столбец и обновите существующие строки с things.type = "LegacyThing". Это на самом деле не STI - он просто использует механизм, встроенный в ActiveRecord.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...