我有一个嵌套模型 items
,我正在尝试将两列相乘 cost
和 quantity
以设置最后一列 价格
。
我需要在保存表单之前设置 price
列,我还需要验证模型。如果在保存前未设置 cost
和 quantity
,则 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_create
或 before_update
回调代替。或者,您可以有选择地设置价格(如果尚未设置):
self.price ||= cost * quantity.round(2)
这就是您要实现的目标吗?
更新:经过一些讨论(见评论),处理这个问题的最佳方法似乎是更新所有子项 items
在before_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/