我发现Money gem的这个附加组件从ECB欧洲中央银行更新(每24小时更新一次),但我不确定如何在使用多种货币的rails应用程序中进行缓存。 / p>
http://github.com/RubyMoney/eu_central_bank
eu_bank ||= EuCentralBank.new
eu_bank.update_rates
#Rails.cache.fetch('rates', :expires_in => 24.hours) { eu_bank.update_rates }
rate = eu_bank.exchange_with(Money.new(100, session[:currency]), "USD").to_f
它具有将速率写入某个文件的功能......但我不确定这也是我想要的。我也在使用具有只读文件系统的heroku。
eu_bank.save_rates("/some/file/location/exchange_rates.xml")
我找不到任何方法来检查对象的年龄。我只想知道每24小时加载一次的最佳选择,并坚持我的整个Rails应用程序。有什么指针吗?
答案 0 :(得分:4)
这可以通过使用Rails低级缓存和before_filter来完成:
class ApplicationController < ActionController::Base
before_filter :set_conversion_rates
def set_conversion_rates
rates = Rails.cache.fetch "money:eu_central_bank_rates", expires_in: 24.hours do
Money.default_bank.save_rates_to_s
end
Money.default_bank.update_rates_from_s rates
end
end
此代码将在24小时内下载一次费率,并将结果保存到缓存(无论您使用何种缓存模块),银行对象将在每次请求时加载它们。
答案 1 :(得分:1)
我刚刚部署了一个解决方案,可以在memcache中缓存汇率并每24小时更新一次。您必须使用最新的money gem,需要提交https://github.com/RubyMoney/eu_central_bank/commit/fc6c4a3164ad47747c8abbf5c21df617d2d9e644。由于我不想每24小时重新启动一次网络流程,我会以before_filter
检查新的汇率(更好的方式?)。实际的Money.default_bank.update_rates
调用可能会被转移到重复的resque作业(或其他)。
LIB / my_namespace / bank.rb
module MyNamespace
class Bank
def self.update_rates_if_changed
if last_updated.nil? || last_updated + 12.hours <= Time.now
update_rates
end
end
def self.update_rates
fetch_rates
# Take latest available currency rates snapshot
[0, 1, 2].each do |days|
date = Date.today - days.days
next unless Rails.cache.exist?(rate_key(date))
begin
rates = Rails.cache.read(rate_key(date))
Money.default_bank.update_rates_from_s(rates)
rescue Nokogiri::XML::SyntaxError
print "error occurred while reading currency rates"
# our rates seem to be invalid, so clear the cache and retry
Rails.cache.delete(rate_key(date))
update_rates
end
break
end
end
private
def self.fetch_rates
return if Rails.cache.exist?(rate_key)
print "Updating currency rates ... "
begin
Rails.cache.write(rate_key, Money.default_bank.save_rates_to_s)
puts "finished"
rescue Exception => ex
puts "error occurred: #{ex.inspect}"
end
end
def self.rate_key(date = Date.today)
["exchange_rates", date.strftime("%Y%m%d")]
end
def self.last_updated
Money.default_bank.last_updated
end
end
end
应用程序/控制器/ application_controller.rb
class ApplicationController
before_filter :check_for_currency_updates
def check_for_currency_updates
MyNamespace::Bank.update_rates_if_changed
end
end
配置/初始化/ money.rb
MyNamespace::Bank.update_rates_if_changed
答案 2 :(得分:0)
由于数据量相对较小,您可以Marshal.dump eu_bank对象,将其存储在memchache中,有效期为24小时(请参阅this doc中的到期日期)。
每次你需要它时,你都会从memchache和Marshal.load中检索它。
如果密钥已从缓存中过期或消失,则会再次获取该密钥以进行实际
答案 3 :(得分:0)
我目前的解决方案不是很优雅,但目前正在运行 - 我正在使用应用启动时的初始化程序和更新/缓存速率。
配置/初始化/ money.rb
# Money exchange
::Money.default_bank = ::EuCentralBank.new
EU_CENTRAL_BANK_CACHE = '/tmp/eu_bank_exchange_rates.xml'
# Right now we update exchange rates on app restart. App is restarted daily after logs rotation,
# Should be ok for now.
if (!File.exist?(EU_CENTRAL_BANK_CACHE)) || File.mtime(EU_CENTRAL_BANK_CACHE) < 23.hours.ago
p "Updating money exchange rates"
::Money.default_bank.save_rates(EU_CENTRAL_BANK_CACHE)
end
::Money.default_bank.update_rates(EU_CENTRAL_BANK_CACHE)