Rails应用程序性能或如何缓存方法结果

时间:2010-06-08 13:45:11

标签: ruby-on-rails associations

我有两种模式:

Program < ActiveRecord::Base
  has_many :events

  def federal_financing
    events.sum(&:federal_financing)
  end

  def regional_financing
    events.sum(&:regional_financing)
  end

  def local_financing
    events.sum(&:local_financing)
  end
end

Event < ActiveRecord::Base
  belongs_to :program
  # events table have this decimal fields: federal_financing, local_financing, regional_financing
end

总是如果我打电话给这三种方法中的一种,我会打电话给另一种方法。因此,每次调用这些方法时,我都希望避免加载事件。目前的解决方案是定义

def after_initialize
  @all_events = events
end

并使用@all_events而不是方法中的事件。但是我不想在加载对象时加载事件 - 只有在调用这三个方法中的任何一个并且其他方法应该使用缓存版本的事件时,我才想要“缓存”事件。

2 个答案:

答案 0 :(得分:1)

我相信您可以使用以下内容每events加载一次program

Program < ActiveRecord::Base
  has_many :events

  def federal_financing
    all_events.sum(&:federal_financing)
  end

  def regional_financing
    all_events.sum(&:regional_financing)
  end

  def local_financing
    all_events.sum(&:local_financing)
  end

  def all_events
    # if @events is not initialized yet or is nil or is false, 
    #    self.events will be loaded. otherwise @events will remain unchanged.
    @events ||= self.events 
  end
end

答案 1 :(得分:0)

Rails将缓存自动加载事件的查询,因此您无需显式缓存事件。但是,要实现此功能,您需要在计算总和之前将事件转换为数组; events.sum表示您希望构造一个SQL查询来计算总和,并且不起作用。

按如下方式更改Program模型:

Program < ActiveRecord::Base
  has_many :events

  def federal_financing
    events.to_a.sum(&:federal_financing)
  end

  def regional_financing
    events.to_a.sum(&:regional_financing)
  end

  def local_financing
    events.to_a.sum(&:local_financing)
  end
end

现在,通过在控制台中启用ActiveRecord日志记录,很容易看到查询确实被缓存:

$ script/console
>> ActiveRecord::Base.logger = Logger.new(STDOUT)
>> p = Program.first
  Program Load (1.0ms)   SELECT * FROM "programs" LIMIT 1
=> #<Program id: 1, created_at: "2010-06-08 15:01:08", updated_at: "2010-06-08 15:01:08">
>> p.federal_financing
  Event Load (1.0ms)   SELECT * FROM "events" WHERE ("events".program_id = 1) 
=> 147
>> p.regional_financing
=> 23
>> p.local_financing
=> 11

如您所见,在第一次调用federal_financing期间,事件仅加载一次。