4

我有一个带有模型的基本发票设置:发票、项目、行项目。

# 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 上设置它,但我认为应该在模型中设置默认值,对吧?如何验证状态的存在并在模型中仍有默认值?

4

3 回答 3

4

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

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

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

查看Rails的回调文档了解更多信息。

于 2012-06-26T17:44:25.730 回答
1

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

至于1:你能举一个例子来说明你是如何创建发票的吗?

于 2012-06-26T17:44:53.220 回答
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
于 2012-06-26T18:30:26.760 回答