在Rails中计算before_validation

时间:2014-05-04 06:00:32

标签: ruby-on-rails ruby-on-rails-3.2

我有两种模特关系:

class Totalsold < ActiveRecord::Base
  attr_accessible :qty, :total_cost, :date, :price_id, :price_attributes
  belongs_to :price
  accepts_nested_attributes_for :price
  before_validation :calculation_total_cost

  private

  def calculation_total_cost
    @price = Price.where(:id => price_id).first
    if qty.nil?
     self.qty = 0
    end
    self.total_cost = qty.to_f * @price.cost
  end
end

class Totalsold < ActiveRecord::Base
 attr_accessible :cost
 has_many :totalsolds
end

calculation_total_cost方法从total_cost * qty cost成功发布before_validation计算。不是很好吗?因为我在提交表单时使用多个创建并查看日志here(我使用pastebin进行粘贴应用日志)。 我的案子还有另外一种方法吗?为更好的表现提供解决方案。

这是创建方法:

def create
  @totalsolds = params[:totalsolds].values.collect { |ts| Totalsold.new(ts) }
     if @totalsolds.all?(&:valid?)
      @totalsolds.each(&:save!)
      redirect_to lhg_path
     else
      render :action => 'new'
     end
end

1 个答案:

答案 0 :(得分:1)

为了提高效率,您需要执行以下操作:

  
      
  • save调用减少为每个对象1个
  •   
  • 将您的功能移至before_save
  •   
  • 从回调中删除所有不必要的查询
  •   

创建

首先,您需要提高create方法的效率。目前,您正在循环使用params[:totalsolds]哈希,并运行验证&amp;每次都保存请求。它对我来说看起来很麻烦:

def create
  totalsold = params[:totalsolds]

  for total in totalsold do
     if total.save #-> should invoke validation
      redirect_to lhg_path
     else
      render :action => 'new'
     end
end

保存前

目前,您正在呼叫before_validation。这意味着每次验证ActiveRecord对象时,您的回调都将运行。这是低效的,尽管可能是您的应用程序工作方式的一部分

我会将其移至before_save回调:

before_save :set_qty
before_save :calculate_total_cost

private

def set_qty
    self.qty = 0 if qty.nil?
end

def calculate_total_cost
    price = Price.find(price_id).cost
    total_cost = qty * price #-> qty doesn't need to be float (I think)
end

不必要的查询

您的主要问题是您使用了许多不需要的查询。 Prime示例:Price.where(:id => price_id).first非常低效 - 只需使用find来提取单个记录(当您处理主键时)

希望这会有所帮助!!