如何在视图中显示支付网关响应消息 - Rails 4,Active Merchant
Posted
技术标签:
【中文标题】如何在视图中显示支付网关响应消息 - Rails 4,Active Merchant【英文标题】:How to display payment gateway response messages in view - Rails 4, Active Merchant 【发布时间】:2014-06-27 07:49:18 【问题描述】:我正在使用带有 Stripe 的 Active Merchant 作为支付网关。一切正常,除了我不知道如何从 Stripe 获取网关响应错误消息(当卡被拒绝、无效等)以在结帐页面上显示给用户。我可以引发一个 StandardError,它会重定向到带有响应消息的错误页面,仅此而已。
订单模型
class Order < ActiveRecord::Base
has_many :order_products
has_many :products, through: :order_products
attr_accessor :card_number, :security_code, :card_expires_on
validate :validate_card, :on => :create
def validate_card
unless credit_card.valid?
credit_card.errors.full_messages.each do |message|
errors[:base] << message
end
end
end
def purchase(basket)
response = GATEWAY.purchase(Product.total_basket_price(basket)*100, credit_card, purchase_options)
unless response.success?
raise StandardError, response.message
end
end
def credit_card
@credit_card ||= ActiveMerchant::Billing::CreditCard.new(
:number => card_number,
:first_name => first_name,
:last_name => last_name,
:verification_value => security_code,
:month => card_expires_on.month,
:year => card_expires_on.year
)
end
def purchase_options
:billing_address =>
:address1 => address_1,
:address2 => address_2,
:city => city,
:country => country_code,
:zip => postal_code
end
end
订单控制器
class OrdersController < ApplicationController
def create
@order = Order.new(order_params)
# @product = basket.find(params[:product_id])
basket.each do |item_id|
@order.order_products.build(product: Product.find(item_id))
end
if @order.save
if @order.purchase(basket)
render "show"
else
render "failure"
end
else
render "new"
end
end
有人可以帮忙吗?
非常感谢
【问题讨论】:
【参考方案1】:简单易懂!
这是一个简单的控制流问题。在 Ruby 中,与大多数语言一样,异常会中断正常的程序流程。正如您现在编写的代码一样,#purchase
在失败时会引发异常。
这很好,是一个完全有效的设计决策。但是与#purchase
交互的代码是这样的:
if @order.purchase(basket)
render "show"
else
render "failure"
end
该代码没有异常处理,因此 Rails 将捕获任何异常,程序流程将停止,您将获得详细的错误页面(在开发模式下)或通用 500 错误页面(在生产模式下) .
由于您自称是 Ruby 和 Rails 的新手,因此稍微替换一下代码可能会更清楚:
# If #purchase is successful, it evaluates to true.
if true
render "show" # 'show' view is rendered as expected. Flow stops.
else
render "failure"
end
# If #purchase fails, it raises an exception.
if raise StandardError, response.message
# ^^^ Exception is raised, flow stops here.
render "show" # This code is never reached.
else # This code is never reached.
render "failure" # This code is never reached.
end
不过,正如我在开头所暗示的那样,一旦您知道问题所在,这很容易解决。您可以使用rescue
简单地处理异常。如果你当前有一个 if/else 块,你可以交换一个 if 块和一个救援块:
if @order.purchase(basket)
render 'show'
end
rescue => e
render 'failure'
根据您的需要,这里还有改进的余地——例如,因为你正在提高和拯救StandardError
,你不能轻易区分网络故障和被拒绝的卡——但它会让你再次行动.
【讨论】:
谢谢@colinm,这有点帮助。我试过谷歌搜索rescue
以及如何使用它,但没有找到很多。【参考方案2】:
经过大量的摆弄和帮助,有效的解决方案是在响应参数哈希中搜索 error
键,如果出现错误,则将消息添加到对象错误中。不是特别优雅,但它现在可以满足我的需求。
订单型号
def purchase(basket)
response = GATEWAY.purchase(Product.total_basket_price(basket)*100, credit_card, purchase_options)
if response.params.key?('error')
self.errors.add :base, response.message
false
else
true
end
end
订单控制器
还切换了控制器中if
语句的顺序,以便def purchase(basket)
在保存顺序之前首先运行,从而可以捕获并显示响应中的错误消息。
if @order.purchase(basket)
if @order.save
render "show"
else
render "new"
end
else
render "new"
end
查看
<%= if @order.errors.any?
@order.errors[:base].to_sentence
end%>
【讨论】:
以上是关于如何在视图中显示支付网关响应消息 - Rails 4,Active Merchant的主要内容,如果未能解决你的问题,请参考以下文章
用于安全支付的最佳支付网关和 Rails gem? [关闭]
在 Spree 支持的 Ruby on Rails 电子商务应用程序中集成印度支付网关 (CCAvenue)