Rails 3:对默认值和关联模型中的validates_presence_of验证错误

时间:2012-06-26 17:27:33

标签: ruby-on-rails ruby model-associations

我有一个基本发票设置模型:Invoice,Item,LineItems。

# invoice.rb
class Invoice < ActiveRecord::Base
  has_many :line_items, :dependent => :destroy
  validates_presence_of :status

  before_save :default_values

  def default_values
    self.status = 'sent' unless self.status
  end
end

# item.rb
class Item < ActiveRecord::Base
  has_many :line_items
  validates_presence_of :name, :price
end

# line_item.rb
class LineItem < ActiveRecord::Base
  belongs_to :item
  belongs_to :invoice 
  before_save :default_values

  validates_presence_of :invoice_id
  validates :item_id, :presence => true
end

模型中还有更多内容,但为了简单起见,我只介绍了上述内容。

我收到以下错误:

2 errors prohibited this invoice from being saved:
  Line items invoice can't be blank
  Status can't be blank

所以有两个问题:

  1. 如果我删除validates :invoice_id, :presence => true我不再收到Line items invoice can't be blank错误消息,但为什么?我想在line_items上验证invoice_id,所有line_items都应该有invoice_id。如何验证line_items上的invoice_id而不会收到错误?

  2. 如果我将其设置为默认值,为什么会出现Status can't be blank错误?我可以在invoices_controller上设置它,但我认为应该在模型中设置默认值,对吧?如何验证状态的存在并且模型中仍有默认值?

3 个答案:

答案 0 :(得分:4)

这两个验证错误都发生了,因为验证在保存之前(以及before_save回调之前)被称为

我假设您正在使用nested_form同时创建发票及其订单项。如果是这种情况,您不希望在订单项上validates :invoice_id, :presence => true - 发票和订单项同时进入,并且发票尚未保存,因此它不会有个身份证。如果您保留验证,则需要先创建并保存空发票,然后再创建订单项,以便invoice_id可用。如果您只想确保在任何编辑后仍设置invoice_id,则可以通过validates :invoice_id, :presence => true, :on => :update强制执行此操作,这将在创建订单项时跳过验证(并且invoice_id尚不可用)。

由于类似的原因,您遇到validates :status, :presence => true的问题 - 通过请求进入的值正在验证,并且“状态”值不存在。验证后运行before_save回调。您可以在before_validationafter_initialization回调中设置默认值,并在运行验证时显示值。

有关详细信息,请查看Rails的Callbacks文档。

答案 1 :(得分:1)

我将从2开始: 在保存之前,只有执行保存之前,意味着,在对象通过验证后即将保存。如果验证失败 - 它将不会被执行。

1: 您能举例说明您是如何创建发票的吗?

答案 2 :(得分:0)

问题1

尝试validates_associated检查相关模型是否全部有效

问题2

与大多数答案一样,在验证后调用before_save。您正在寻找的魔法是after_initialize,它会在调用对象的initialize方法后运行。

class Invoice < ActiveRecord::Base
  after_initialize :default_values
  validates :status, presence: true

private

  def default_values
    self.status ||= 'sent'
  end
end