如果事务块失败,如何呈现新的?

时间:2014-02-13 18:54:45

标签: ruby-on-rails ruby ruby-on-rails-4 stripe-payments

我正在使用Stripe来处理付款。我使用事务块的原因是为了确保以下成功或根本没有:

  • 付款记录将写入db
  • 执行条纹付款

我无法工作的一件事是rescue块。我故意给Stripe一张无效的信用卡以使交易失败。但是,当它失败时,它不会render :new

  def create
    manager = current_session.manager
    plan = Plan.find params[:plan_id]

    Payment.transaction do
      Payment.create(
        plan_id: params[:plan_id],
        management_id: current_session.management.id
      )

      begin
        stripe_customer = Stripe::Customer.retrieve(manager.payment_provider_customer_id) if manager.try(:payment_provider_customer_id).present?

        if stripe_customer.present?
          # do something here
        else
          stripe_customer = Stripe::Customer.create(
            email: manager.email,
            metadata: {
              manager_id: manager.id
            }
          )
          stripe_customer.cards.create(card: 'zzzzzzzzzzzz')
          stripe_customer.subscriptions.create(plan: plan.payment_provider_plan_id)
        end
      rescue => error
        # If any of the Stripe requests fail, then we must also rollback the payment transaction
        puts "Error: #{error}"
        raise ActiveRecord::Rollback
        render :new
      else
        redirect_to root_path, notice: 'Thank you. Your payment is being processed.'
      end
    end
  end

我得到的错误是:

Missing template dashboard/payments/create, dashboard/application/create, application/create with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee, :slim]}

2 个答案:

答案 0 :(得分:1)

问题是你提出了ActiveRecord :: Rollback异常,然后尝试渲染:new。异常引发后的代码永远不会执行。我建议你分开管理事务的方法,如下所示:

def create
  your_processing_transaction_method
  redirect_to root_path, notice: 'Thank you. Your payment is being processed.'
rescue ActiveRecord::Rollback
  render :new and return
end

private

def your_processing_transaction_method
  manager = current_session.manager
  plan    = Plan.find params[:plan_id]

  Payment.transaction do
    Payment.create(
      plan_id: params[:plan_id],
      management_id: current_session.management.id
    )

    begin
      stripe_customer = Stripe::Customer.retrieve(manager.payment_provider_customer_id) if  manager.try(:payment_provider_customer_id).present?

      if stripe_customer.present?
        # do something here
      else
        stripe_customer = Stripe::Customer.create(
          email: manager.email,
          metadata: {
            manager_id: manager.id
          }
        )
        stripe_customer.cards.create(card: 'zzzzzzzzzzzz')
        stripe_customer.subscriptions.create(plan: plan.payment_provider_plan_id)
      end
    rescue => error
      raise ActiveRecord::Rollback
    end
  end
end

请记住,这显然不是最好的设计决策(即在控制器中处理所有这类事务处理和业务代码)。控制器应该只负责接收请求,将其交给域模型并根据域的响应返回响应。

将此私有方法提取到服务类是一种更好的方法,但我认为它可以帮助处理事务/呈现问题。

答案 1 :(得分:0)

问题是你在打电话

render :new

你需要

render :new and return

由于没有返回,代码在渲染后继续,然后隐式渲染创建模板