Rails - обновить модель "в будущем"

Нам нужно добавить функцию, которая позволяет пользователю решить, прежде чем вносить изменения в модель, когда это изменение повлияет (например, с завтра в 19:43)

Проблема заключается в том, что наша модель имеет множество зависимостей со многими проверками, и есть вероятность, что будущие изменения будут конфликтовать друг с другом:

  • Сделайте изменение A завтра (проверка проверки прохождения)
  • Внесите изменения B сейчас - это изменение может привести к неправильному изменению A.

Есть ли известное решение /Gem для этой проблемы? Каков наилучший подход для решения этой проблемы?

Спасибо.

Ответ 1

Вы можете дублировать веб-сервер и БД и иметь один экземпляр на сегодняшний день и один на завтра. В полночь переопределите "завтрашнюю" базу данных с "сегодняшним".

Ответ 2

Я предлагаю вам использовать State Machines. Вы можете прочитать wiki для быстрого ознакомления. И есть много драгоценных камней, которые вы можете использовать: ruby-toolbox. Каждый из них имеет свои плюсы и минусы, но стандартное поведение позволяет определять состояния, события и переходы между событиями, а также некоторые из них обеспечивают обратные вызовы, проверки и условия.

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

Это зависит от бизнес-правил вашей системы, но вы можете установить состояние в точке "1. Сделать изменение A завтра (тест проверки валидации)", возможно, "замороженным", а затем, когда наступит точка "2. Внесите изменения B сейчас - это изменение может привести к тому, что изменение A будет недействительным", подтвердите, может ли это изменение быть выполнено с этим статусом.

Затем, когда ваша система изменится, будет легко добавить новые события, статусы и переходы и поддерживать соответствие системы с обновленными бизнес-правилами.

Ответ 3

Похож на очень старый вопрос. Но поскольку я реализовал нечто подобное, я отвечаю на это:

Это можно легко достичь, используя камень Sidekiq (который работает с Redis). Я действительно использовал этот камень для решения подобной ситуации.

Основное видение Sidekiq - включение фоновых заданий в приложениях Rails. Наряду с этим Sidekiq предоставляет дополнительные функции, такие как задержка в определенном вызове объекта ActiveRecord.

Вот как это сделать:

User.delay_for(2.weeks).whatever

Подробнее здесь:

https://github.com/mperham/sidekiq/wiki/Delayed-extensions

Ответ 4

Я предлагаю вам использовать функции отката: http://api.rubyonrails.org/classes/ActiveRecord/Rollback.html

Допустим, у вас уже есть "Изменить А" в очереди на завтра, которая прошла проверку. И кто-то делает Изменить B на ту же модель, вы можете сделать:

  • транзакция с открытым откатом.
  • Сохранить новое изменение B в модели
  • Подтвердить изменение A, ожидающее в очереди.
  • Если валидация при изменении A не выполняется, транзакция отката, которая вернет все изменения B в неизмененное состояние.
  • Сообщать пользователю, что он делает изменение B, что его изменение противоречиво. Изменить A.

Упрощенный пример метаданных:

Transient.transaction do
  model = get_transient_model
  model.change = change_B
  model.save

  model.change = QueueChanges.get_change_A
  if not model.valid?
    notification_system.notify_user_about_conflict!
    raise ActiveRecord::Rollback, "Conflict!"
  else
    # we are good to go!
  end
end