validation - 在嵌套模型上验证之前

标签 validation ruby-on-rails-4 nested-attributes

我有一个嵌套模型 items,我正在尝试将两列相乘 costquantity 以设置最后一列 价格。 我需要在保存表单之前设置 price 列,我还需要验证模型。如果在保存前未设置 costquantity,则 before_validation 回调显然会中断。 关于如何将这些列相乘并验证模型的任何想法?

这是我的代码item.rb

class Item < ActiveRecord::Base
belongs_to :invoice

 validates :invoice_id, presence: true
 validates :name, presence: true
 validates_presence_of :quantity, :cost, :price

 before_validation :set_price

 def set_price
    self.price = cost * quantity.round(2)
 end
end

这是我的父模型 invoice.rb

class Invoice < ActiveRecord::Base
belongs_to :user
has_many :items

accepts_nested_attributes_for :items, :reject_if => :all_blank, :allow_destroy => true

validates :sender, presence: true
validates_associated :items

before_save :increment_invoice_number, :set_amount

private

def increment_invoice_number
    if published == true
        self.invoice_number = user.invoices.where(:published => true).count + 1
    end
end

def set_amount
    self.amount = items.map(&:price).sum             
end

结束

最佳答案

如果您总是要在每次保存时更新价格,则不需要验证它的存在,因此只需将其从验证中删除并添加 before_save回调,它将在验证后 被调用,因此可以保证您拥有有效的成本和数量字段。这是 Rails 指南中讨论此问题的位置的链接: http://guides.rubyonrails.org/active_record_callbacks.html#available-callbacks

这是一个例子:

class Item < ActiveRecord::Base
  belongs_to :invoice

  validates :invoice_id, presence: true
  validates :name, presence: true
  validates_presence_of :quantity, :cost

  before_save :set_price

  def set_price
    self.price = cost * quantity.round(2)
  end
end

如果您想在创建或更新时设置价格,您可以使用before_createbefore_update回调代替。或者,您可以有选择地设置价格(如果尚未设置):

self.price ||= cost * quantity.round(2)

这就是您要实现的目标吗?

更新:经过一些讨论(见评论),处理这个问题的最佳方法似乎是更新所有子项 itemsbefore_save父回调 invoice ,因为每次 invoice 时都会调用它被保存。下面是一个示例实现 - 我还从您的原始代码中删除了一些验证语句,并使用新语法组合了所有内容。此外,items无论何时通过 nested_attributes 关联进行更新,都将得到验证。

class Item < ActiveRecord::Base
  belongs_to :invoice

  validates :invoice_id, :name, :quantity, :cost, presence: true

  def set_price
    self.price = cost * quantity.round(2)
  end
end

class Invoice < ActiveRecord::Base
  belongs_to :user
  has_many :items

  accepts_nested_attributes_for :items, :reject_if => :all_blank, :allow_destroy => true

  validates :sender, presence: true

  before_save :increment_invoice_number, :update_prices, :set_amount

  private

  def increment_invoice_number
    if published == true
      self.invoice_number = user.invoices.where(:published => true).count + 1
    end
  end

  def update_prices
    items.each(&:set_price)
  end

  def set_amount
    self.amount = items.map(&:price).sum             
  end
end

关于validation - 在嵌套模型上验证之前,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35530996/

相关文章:

javascript - 在 AJAX 中处理 PHP header

ruby-on-rails-3 - Rails 3.2 - accepts_nested_attributes_for 并加入模型

ruby-on-rails - rails accepts_nested_attributes_for 和验证... Rails 2.3.11

ruby-on-rails - 如何正确设置此嵌套关联?

java - 验证表单 struts2 管理输入

ruby-on-rails - 通过父属性进行 ActiveRecord 验证

javascript - jQuery 插件冲突 - 验证和 jQuery 表单

ruby-on-rails - 希望能够根据两个不同的值进行多行插入

ruby-on-rails - 我可以强制 Rails 自动加载命名空间而不嵌套在文件夹中吗?

javascript - 根据网络带宽自动选择合适的视频质量?