Created
January 2, 2015 15:10
-
-
Save sigra/632561139e7e245c4a78 to your computer and use it in GitHub Desktop.
Rails multiple currency support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ApplicationController < ActionController::Base | |
include HasCurrency | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
config.currencies = %w(EUR GBP SEK USD CZK) | |
config.country_currencies = { 'DK' => 'DKK', 'SE' => 'SEK', 'UK' => 'GBP', 'US' => 'USD', 'CZ' => 'CZK' } | |
config.country_locales = { 'SE' => :se, 'DE' => :de, 'ES' => :es, 'CS' => :cs } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module HasCurrency | |
extend ActiveSupport::Concern | |
included do | |
before_action :set_conversion_rates | |
before_action :add_user_currency, if: -> { defined?(current_user) && current_user.present? } | |
def current_currency | |
@current_currency ||= get_current_currency | |
end | |
helper_method :current_currency | |
def currency_info | |
@currency_info ||= get_current_currency_info | |
end | |
helper_method :currency_info | |
end | |
private | |
def set_conversion_rates | |
rates = Rails.cache.read('money:exchange_rates') | |
Money.default_bank.update_rates_from_s(rates) if rates.present? | |
end | |
def get_current_currency | |
if currency_exists?(params[:currency]) | |
cookies[:currency] = params[:currency] | |
elsif current_user.present? && currency_exists?(current_user.currency) | |
current_user.currency | |
elsif currency_exists?(cookies[:currency]) | |
cookies[:currency] | |
else | |
cookies[:currency] = currency_by_ip(request.remote_ip) | |
end | |
end | |
def get_current_currency_info | |
current = Money::Currency.find(get_current_currency) | |
default = Money.default_currency | |
{ | |
rate: Money.default_bank.get_rate(default, current), | |
symbol_first: current.symbol_first?, | |
name: current.name, | |
symbol: current.symbol, | |
code: current.iso_code, | |
subunit_to_unit: current.subunit_to_unit | |
} | |
end | |
def currency_exists?(currency) | |
currency.present? && EuCentralBank::CURRENCIES.select { |c| | |
c.downcase == currency.downcase | |
}.size == 1 | |
end | |
def add_user_currency | |
unless current_user.currency? | |
current_user.update_attribute :currency, currency_by_ip(current_user.current_sign_in_ip) | |
end | |
end | |
def currency_by_ip(ip) | |
geo = Geocoder.search(ip).try(:first) | |
if geo.present? | |
Country.new(geo.country_code).try(:currency_code) || Money.default_currency.to_s | |
else | |
Money.default_currency.to_s | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gem 'eu_central_bank' | |
gem 'geocoder' | |
gem 'money-rails' | |
# for rate worker | |
gem 'sidekiq' | |
gem 'sidetiq' | |
gem 'sinatra', require: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module MoneyHelper | |
def localized_price(price) | |
currency = converted_price(price).currency | |
number_to_currency(converted_price(price).to_f, | |
precision: currency.exponent.to_i, | |
strip_insignificant_zeros: true, | |
separator: currency.decimal_mark, | |
delimiter: currency.thousands_separator, | |
unit: currency.symbol, | |
format: currency.symbol_first ? "%u%n" : "%n%u" | |
) | |
end | |
def converted_price(price) | |
price = Money.new(price) unless price.is_a?(Money) | |
converted = Money.new(price).exchange_to(current_currency).to_f | |
ceiled = if %w(EUR GBP USD).include?(current_currency) | |
sub = currency_info[:subunit_to_unit] / 10 | |
(converted * sub).ceil / sub.to_f | |
else | |
converted.ceil | |
end | |
Money.new(ceiled * currency_info[:subunit_to_unit], current_currency) | |
rescue | |
price | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rails g migration AddCurrencyToUsers currency:string |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CacheExchangeRatesWorker | |
include Sidekiq::Worker | |
include Sidetiq::Schedulable | |
sidekiq_options retry: false, unique: true | |
recurrence { minutely(5) } | |
def perform | |
rates = Money.default_bank.save_rates_to_s | |
Rails.cache.write('money:exchange_rates', rates) | |
rates | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment