如何在请求中记忆哈希?

时间:2017-05-06 14:06:06

标签: ruby-on-rails ruby activerecord memoization

在我的Rails应用程序中,我有一个非常昂贵的函数,每天从外部服务获取一堆转换率:

require 'open-uri'

module Currency

  def self.all
    @all ||= fetch_all
  end

  def self.get_rate(from_curr = "EUR", to_curr = "USD")
    all[from_curr][to_curr]
  end

  private

    def self.fetch_all
      hashes = {}
      CURRENCIES.keys.each do |currency|
        hash = JSON.parse(open(URI("http://api.fixer.io/latest?base=#{currency}")).read)
        hashes[currency] = hash["rates"]
      end
      hashes
    end

end

有没有办法存储这个函数的结果(哈希)来加快速度?现在,我正在尝试将它存储在一个实例变量@all中,这会加快它的速度,但它不会在请求之间保持不变。如何在请求中保留它?

1 个答案:

答案 0 :(得分:3)

使用以下代码在初始值设定项中创建一个文件currency_rates.rb

require 'open-uri'
hashes = {}
CURRENCIES.keys.each do |currency|
  hashes[currency] = JSON.parse(open(URI("http://api.fixer.io/latest?base=#{currency}")).read)["rates"]
end
CURRENCY_RATES = hashes

然后编写以下每日运行的rake任务:

task update_currency_rates: :environment do
  require 'open-uri'
  hashes = {}
  CURRENCIES.keys.each do |currency|
    hashes[currency] = JSON.parse(open(URI("http://api.fixer.io/latest?base=#{currency}")).read)["rates"]
  end
  Constant.const_set('CURRENCY_RATES', hashes)
end

唯一的缺点是,每次部署新版本的app /重启时都会运行它。如果你对它好的话你可以使用它。

如果您使用memcachier之类的缓存,那么您可以避免这种情况,那么您可以这样做,

def currency_rates
  Rails.cache.fetch('currency_rates', expires_in: 24.hours) do
    # write above code in some method and call here which will return hash and thus it will be cached.
  end
end