rails money with money gem(eu_central_bank)

时间:2010-09-27 16:23:14

标签: ruby-on-rails ruby caching memcached currency

我发现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应用程序。有什么指针吗?

4 个答案:

答案 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)