0

我想在很多方面我仍然是一个新手,对这些 Rails 的一些东西。我有用于付款的 ActiveRecord 模型。但是,它只有两件事被添加到它的表中,一旦我们从 authorize.net 得到积极的回应,这些事情就会完成。在这个模型的控制器中,我有我的购物车表单。在购物车表单中,我有从@client 和信用卡信息中提取的默认值的账单信息。它看起来有点像这样:

<%= form_for @payment, :url => { action: "checkout" } do |f| %>
...show errors ...
<%= f.fields_for @client do |ff| %>
    <%= ff.label :firstname, 'First Name*' %>
    <%= ff.text_field :firstname %>
    ...more fields ....
    <%= ff.label :zip, 'Zip*' %>
    <%= ff.text_field :zip %>
<% end %>
<%= f.label :cardnumber, 'Card Number*' %>
<%= f.text_field :cardnumber %>
... more cc info fields ...
<% end %>

现在在模型中,我添加了 attr_accessor :cardnumber 和其他卡信息字段。

对于这些,我没有任何 getter 或 setter 方法(也许这就是我所缺少的)。

但是,我在付款模型中确实有这个:

validates :zip, presence: true, numericality: true
validates :cardnumber, presence: true, numericality: true

然而,到目前为止,表单将一起绕过此验证并前往结帐。任何帮助将不胜感激!如何让这些验证正常工作?

4

1 回答 1

1

如果你想深入了解技术细节,大多数 Rails 的内置验证器都继承自 ActiveModel::EachValidator,并且此验证器通过#read_attribute_for_validation 显式检查来自 ActiveModel 的属性集合。如果 #zip 和 #cardnumber 已使用 attr_accessor 设置,它们很可能不是#attributes 的一部分,因此被验证器跳过。

最简单的解决方法是编写一个验证 zip/cardnumber 的私有方法,然后使用该验证方法的名称调用 .validates。Koz 推荐的模式看起来像这样......

class Payment
  attr_accessor :zip

  validate :assure_zip_not_blank

  private
    def assure_zip_not_blank
      errors.add(:zip, 'cannot be blank') if zip_blank? && new_record?
    end

    def zip_blank?
      self.zip.blank?
    end
end

在这种特殊情况下,将验证分为两种方法(assure_zip_not_blank 和 zip_blank?)可能有点矫枉过正,但当逻辑变得更复杂和/或您可以重用逻辑时,它会很有帮助。

于 2013-11-18T00:52:45.417 回答