我想要的两件事:
a)我希望只有在API调用成功时才能在db中保存记录
b)我只想在db记录成功保存的情况下执行API调用
目标是保持本地(在数据库中)存储的数据与Stripe上的数据保持一致。
@payment = Payment.new(...)
begin
Payment.transaction do
@payment.save!
stripe_customer = Stripe::Customer.retrieve(manager.customer_id)
charge = Stripe::Charge.create(
amount: @plan.amount_in_cents,
currency: 'usd',
customer: stripe_customer.id
)
end
# https://stripe.com/docs/api#errors
rescue Stripe::CardError, Stripe::InvalidRequestError, Stripe::APIError => error
@payment.errors.add :base, 'There was a problem processing your credit card. Please try again.'
render :new
rescue => error
render :new
else
redirect_to dashboard_root_path, notice: 'Thank you. Your payment is being processed.'
end
以上内容将起作用,因为如果记录(第5行)没有保存,则其余代码不会执行。
但是如果我需要在API调用之后保存@payment
对象,那该怎么办?因为我需要为@payment
对象分配API结果中的值。举个例子:
@payment = Payment.new(...)
begin
Payment.transaction do
stripe_customer = Stripe::Customer.retrieve(manager.customer_id)
charge = Stripe::Charge.create(
amount: @plan.amount_in_cents,
currency: 'usd',
customer: stripe_customer.id
)
@payment.payment_id = charge[:id]
@payment.activated_at = Time.now.utc
@payment.save!
end
# https://stripe.com/docs/api#errors
rescue Stripe::CardError, Stripe::InvalidRequestError, Stripe::APIError => error
@payment.errors.add :base, 'There was a problem processing your credit card. Please try again.'
render :new
rescue => error
render :new
else
redirect_to dashboard_root_path, notice: 'Thank you. Your payment is being processed.'
end
您会在API调用后发现@payment.save!
。这可能是一个问题,因为在DB尝试保存记录之前,API调用已运行。这可能意味着,一个成功的API调用,但是数据库提交失败。
针对此方案的任何想法/建议?
答案 0 :(得分:8)
您无法执行API => DB和DB => API同时(听起来像一个无限的执行条件),至少我无法想象如何实现这个工作流程。我了解您的数据一致性需求,因此我建议:
@payment.valid?
(可能使用自定义方法,如valid_without_payment?
)payment_id
)
可替换地:
payment_id
payment_id
(api响应)更新记录
where(payment_id: nil)
)并将其删除我认为这两个选项都是可以接受的,您的数据将保持一致。