0

我有一个模型叫PaymentNotifications. 只有在 Paypal 有效时,它才用于记录付款。我需要检查他们给我的交易代码是否与我在发布表格后从他们那里得到的交易代码相同。

所有这些都有效。然后我要做的是根据以下一些标准检查它是否有效:

在控制器中,我有以下内容:

tx = params[:tx] 
paypal_data = get_data_from_paypal(tx)
res_hash = create_hash(paypal_data) 
@payment_notification = PaymentNotification.new(:params => res_hash, :quotation_id => res_hash['invoice'],:status => res_hash["payment_status"],:transaction_id => res_hash["txn_id"])
if paypal_data["SUCCESS"] && @payment_notification.is_valid?(tx) && @payment_notification.save
  redirect_to thankyou_path(:id => @payment_notification.quotation_id)
else
  render '/pages/error'
end

然后在模型中我运行我的方法is_valid?

validates :params, :quotation_id, :status, :transaction_id, presence: true
validates :transaction_id, :uniqueness => true

def is_valid?(tx)
  amount_paid_valid?(params["payment_gross"]) && transaction_valid?(tx) && is_quotation_unpaid? 
end

def transaction_valid?(tx)
  if tx != transaction_id
    errors.add(:transaction_id, "This transaction is not valid")
    return false
  else
    return true
  end
end

def is_quotation_unpaid?
  if quotation.unpaid?
    return true
  else
    errors.add(:quotation_paid, "This quotation has already been paid.")
    return false
  end
end

def amount_paid_valid?(amount_paid)
  if amount_paid.to_i == quotation.price.to_i
    return true
  else
    errors.add(:amount_paid, "The amount paid does not match the price quoted.")
    return false
  end
end

注意::amount_paid并且:quotation_paid不是属性。它们只是错误消息的键。

我想我在这里错过了这艘船,因为必须有一种方法可以通过 Rails 内置的验证来做到这一点,但我对 Rails 还不是很擅长。有人可以帮我重构它,以便更容易维护并符合最佳实践吗?

4

1 回答 1

1

这里的主要问题是您正在重新实现 Rails 已有的东西——即检查 AR 对象是否有效的方法。如果您使用您的方法而不是内置方法,#valid?您的对象将继续传递此类操作#save#create即使它们不应该传递。

为了在调用内置验证时将您的自定义方法纳入其中并包含它们,只需将它们用作模型中的自定义验证,如下所示:

validates :params, :quotation_id, :status, :transaction_id, presence: true
validates :transaction_id, :uniqueness => true
validate :amount_paid_should_match_quote, :quotation_should_be_unpaid
validates_associated :transaction

private

def amount_paid_should_match_quote
  if amount.to_i != quotation.price.to_i
    errors.add(:amount, "does not match the price quoted")
  end
end

def quotation_should_be_unpaid
  if quotation.paid?
    errors.add(:quotation, "has already been paid")
  end
end

需要注意的几个项目:

  1. 验证方法不应带参数,因为它们是测试现有属性的实例方法。
  2. 避免在模型中引用参数。处理请求是控制器的工作。
  3. 您只需要处理方法中的非通过场景。true当对象有效时不要担心返回,这取决于 Rails。
  4. 不要编写方法来验证关联。只是validates_associated用于那个。
  5. 如果您将自定义方法重命名为更能描述他们试图强制执行的实际行为,这会有所帮助。我试图给你一个建议,但你可以使用任何你喜欢的东西。

您可以在Rails Guides Validations 文档中了解有关自定义验证的更多信息。

于 2013-09-10T16:31:58.640 回答