Ruby on Rails中带有条带的回滚方法更改

问题描述 投票:0回答:1

如果错误,我会尝试回退订阅更改,但是我很难确定这样做的好方法。我现在不希望使用网络挂钩。

有更好的方法吗?如您所见,我正在尝试事件,然后手动回滚每个事件。我觉得这需要很好的重构。

def change_plan(subscription:, to_plan:, coupon: nil)
  require_args(subscription: subscription, to_plan: to_plan)
  events = []
  begin
    from_plan = subscription.plan
    api_sub = update_subscription_plan(subscription: subscription, to_plan: to_plan,
                                           coupon: coupon, proration_date: get_proration_date, prorate: true)
    events<<'api_updated'
    subscription.update!(plan:           to_plan,
                         coupon:         coupon,
                         item_api_id: api_sub.items.data[0].id)
    events<<'db_updated'
    invoice = create_invoice(subscription)
    events<<'created_invoice'

    invoice = invoice.pay
    events<<'invoice_paid'

  rescue Stripe::StripeError => e
    subscription.errors[:base] << e.message
    if events.include?('api_updated')
      stripe_sub = update_subscription_plan(subscription: subscription, to_plan: from_plan,
                                             coupon: coupon, proration_date: get_proration_date, prorate: false)
    end
    if events.include?('db_updated')
    subscription.update!(plan:           from_plan,
                         coupon:         coupon,
                         item_api_id: api_sub.items.data[0].id)
    end

    if events.include?('created_invoice')
      void_invoice(invoice.id)
    end
    subscription.errors[:base] << "Upgrade failed, please contact us."
  end
  subscription
end
ruby-on-rails ruby ruby-on-rails-5
1个回答
0
投票

您可以将交互器模式与出色的interactor宝石一起使用,您可以在此处找到https://github.com/collectiveidea/interactor。交互器就像服务,只有一种目的的小类,被一一称为。 gem提供了rollback方法,因此您可以轻松回滚任何进程。

值得一提的是,这里有互动者和组织者。您可以将交互程序视为服务,将组织者视为按定义顺序触发的一组链接的交互程序。您可以创建ChangePlan管理器:

class ChangePlan
  include Interactor::Organizer

  organize UpdateSubscriptionPlan, UpdateSubscription, CreateInvoice, PayInvoice
end

这里是您的交互器以及rollback方法,在发生Stripe::StripeError错误的情况下,这些方法将还原更改。

class UpdateSubscriptionPlan
  include Interactor

  def call
    context.api_sub = update_subscription_plan(
      subscription: context.subscription,
      to_plan: context.to_plan,
      coupon: context.coupon,
      proration_date: get_proration_date,
      prorate: true
    )
  rescue Stripe::StripeError => error
    context.fail!(error: error.message)
  end

  def rollback
    update_subscription_plan(
      subscription: context.subscription,
      to_plan: context.from_plan,
      coupon: context.coupon,
      proration_date: get_proration_date,
      prorate: false
    )
  end
end
class UpdateSubscription
  include Interactor

  delegate :subscription, :to_plan, :coupon, :api_sub, :from_plan, to: :context

  def call
    subscription.update!(
      plan: to_plan,
      coupon: coupon,
      item_api_id: api_sub.items.data[0].id
    )
  end

  def rollback
    subscription.update!(
      plan: from_plan,
      coupon: coupon,
      item_api_id: api_sub.items.data[0].id
    )
  end
end
class CreateInvoice
  include Interactor

  def call
    context.invoice = create_invoice(context.subscription)
  rescue Stripe::StripeError => error
    context.fail!(error: error.message)
  end

  def rollback
    void_invoice(context.invoice.id)
  end
end
class PayInvoice
  include Interactor

  def call
    context.invoice.pay
  end
end

具有这种结构,您现在可以这样称呼他们:

outcome = ChangePlan.call(
  subscription: subscription,
  to_plan: to_plan,
  coupon: coupon
)

unless outcome.success?
  subscription.errors[:base] = 'Upgrade failed, please contact us.'
end

您可以在https://github.com/collectiveidea/interactor#rollback上阅读有关交互器中回滚的更多信息。我只给了您伪代码,但是按此顺序操作可以使您在某个动作失败时自动回滚所有先前的动作。这是交互器的主要优点。

© www.soinside.com 2019 - 2024. All rights reserved.