Допустим, у нас есть следующий сценарий:
class MyModel < ActiveRecord::Base
after_save :throw_after_save
after_commit :throw_after_commit
private
def throw_after_save
raise "raising on after_save"
end
def throw_after_commit
raise "raising on after_commit"
end
end
class MyController < ApplicationController
def callback
begin
MyModel.new(params).save
rescue
flash[:alert] = "Failed persisting to external system. Try again."
Airbrake.notify(
error_class: "External System Persistence",
error_message: "External System Persistence: Failed to persist data",
parameters: params
)
end
redirect_to root_path
end
end
Получаем обратный вызов от внешней системы (где пользователь заполняет какие-то данные и создает временный набор атрибутов для учетной записи).
Предположим, что мы хотим сохранить некоторые данные локально после того, как нам будет сделан обратный вызов. После того, как эти данные будут сохранены, мы хотим сделать вызов внешней системе, чтобы завершить процесс создания учетной записи. Внешняя система должна вернуть результат, информирующий нас об успехе, с некоторыми дополнительными данными, которые нам необходимо сохранить локально. Мы также знаем, что в некоторых исключительных случаях сохранение в удаленной системе не будет успешным (скажем, система недоступна или что-то пойдет не так на их стороне).
Цель состоит в том, чтобы зафиксировать внешние исключения сохраняемости, а также успехи и действовать соответствующим образом. В случае успеха все в порядке: дополнительные данные сохраняются локально, происходит redirect_to root_path
. Однако в случае исключений мы хотели бы указать это пользователю (возможно, установить flash[:alert]
для отображения в представлении).
Мы пытались использовать ActiveRecord::Callbacks
, чтобы генерировать исключение из моделей after_save
и after_commit
и обрабатывать это исключение в контроллере, устанавливая предупреждение и, возможно, передавая исключение в какую-либо систему уведомления об исключениях (например, Airbrake). В случае after_save
исключение выбрасывается моделью и ловится контроллером, но запись не сохраняется (а у нас есть требование сохранения частичных данных даже в случае исключений с внешней системой - это не приемлемый). В случае after_commit
исключение не генерируется и принимается контроллером, но частичная запись сохраняется. Это означает, что мы не можем уведомить пользователя об исключении (если только мы не реализуем какой-либо механизм отправки уведомлений, что является излишним).
Как оказалось, мы можем устанавливать ошибки в модели на after_save
, и это хорошо. Но является ли это хорошим общим шаблоном для такого сценария?