Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Currency loading via ActiveRecord from DB? #8

Closed
pavolzbell opened this Issue · 9 comments

5 participants

@pavolzbell

It will be very nice if the Currency objects could be loaded (and stored, if modified) from a table in DB via ActiveRecord (currently they are loaded only from the config JSON files I think), is something like that possible to be implemented in the near future?

@alup
Owner

@pavol-zbell you mean the whole table which holds the globally available currencies for Money library? If this is what you mean then it is not possible.

On the other hand, there is support for keeping specific currencies per model (per database table). You may add a currency column in your model's table in order to achieve this. And then you use monetize macro.

@pavolzbell

Yes, this is what I mean. So if it is not possible now it also means that it won't be possible in the future? For example it would be very handy to have the attributes of a currency stored in a DB table, especially the priority.

I know that you can keep specific currencies per model.

@alup
Owner

Can you give an example of how is this going to be used. Do you want to dynamically change priority? All the other attributes of currency are more or less static data. So, it doesn't make sense to put them in a DB table, except for special cases.

I will leave your issue open in order to be discussed with other people too. If we'll have more requests on this feature we will plan its implementation.

P.s. You could also provide a patch if you want :), I can help you in reviewing.

@pavolzbell

For example, consider three models: MyCurrency (table with columns: id, priority, iso_code, ...), ExchangeRate (table with columns: id, from_currency_id, to_currency_id, rate, created_at) and Price (table with columns: id, value_1, value_1_currency_id, value_2, value_2_currency_id).. I would like to have a set of specific currencies in DB to which I will collect exchange rates daily. The MyCurrency model will automatically map to Money::Currency (which is not possible right now, btw I agree, maybe it is not a good idea to store all the attributes of a currency in DB). The Price model holds two different Money objects (value_1 and value_2), it holds both subunits and currencies (I am not quite sure, but I think this can not be achieved automatically right now -- I mean that you can change the name of the column holding cents, but not the column holding currency, all you can do is play with :with_currency => :eur, but I would like to see soething like :with_currency => :table_column (such as value_1_currency_id). If I am wrong, please correct me). The main idea is these three models are bond by a currency id (an integer, currently not possible), not by iso_code (3 char. string, currently possible, but not so automatically achievable).

Oh, I would like to, but I don't think I have enough experience. I started with Ruby and RoR only a couple months ago, and I am not sure how the most of the things are internally working.

@ep-wac

I'd like to give my +1 for keeping currencies in a table (currencies) and for storing exchange_rates in a(nother) table (exchange_rates) - using f.ex the nordea gem for loading fresh exchange_rates into that table every so often

Reason would be to only handle/present/allow using/calculating/exchanging in currencies relevant to users - and for admin to manage currencies requested. Finally tables with monetized fields would hold a currency_id, pointing to the currency used in a particular row in that table. Limiting the number of currencies available, would reduce the number of errors on keying in data pertaining to monetized fields (I have international customers to whom dollars are dollars - no matter if canadian or us - and they have a hard time adjusting)

the load_currencies could build the Hash from data table - not data file - something along the lines of:

def load_currencies
    currencies = ::Currency.all.each.map {|c| { :"#{c.iso_code}"=> c.as_json} }
end

ohh - and admin could manage currencies by localized names, short-cut-names, etc - and allow users to select currencies by these 'names'

@alup
Owner

Indeed, I think that this could be an option in the future. In general, currencies are more or less static entities, so keeping them in a db table make sense only for special cases. For example, custom currencies are candidates for this. Another use case, would be aliasing currencies as @ep-wac said and altering priorities. But, for the most of the users of this library, I believe the simplest case of using a virtual currency attribute (model level, or column level) is enough. So, they can keep their db schema clean. However, I would like to support this option (but not as the default), too. You are welcome to contribute on this.

Exchange rates is another issue. It would be nice to keep a table for rates and try to synchronize the data with fresh values. @ep-wac, can you open a new ticket for this, describing in more details what you would like to support?

@semmons99, @weppos what do you think?

@semmons99
Owner

@alup sounds like you're heading down the right path. Get a minimal viable product that works for most cases before moving on to the special stuff.

@ep-wac

@semmons99 - totally agree -

@alup - will do in a sec and pertaining to the loading of currencies - my initial sketch was inaccurate to say the least :) Perhaps money-rails could probe the app for a currency model and if found - load_currencies from that model and otherwise continue as always -

I actually ended up doing like this:

class Currency < AbstractActionBase

  has_many :countries                                # some currencies - like the euro - is used by more countries
  has_many :exchange_rates

  after_save :register_currencies

  private

    def register_currencies
      Currency.all.each do |curr|
        curr = build_money_compatible_currency(curr)
        Money::Currency.register(curr)
      end
    end

    #
    # using the Money Gem requires this definition of currencies
    #
    # "priority": 100,
    # "iso_code": "BMD",
    # "name": "Bermudian Dollar",
    # "symbol": "$",
    # "subunit": "Cent",
    # "subunit_to_unit": 100,
    # "symbol_first": true,
    # "html_entity": "$",
    # "decimal_mark": ".",
    # "thousands_separator": ",",
    # "iso_numeric": "060"
    def build_money_compatible_currency(curr)
      cur = {}
      curr.attributes.each{ |k,v| cur[k.to_sym] = v }
      cur[:symbol_first] ||= true
      cur[:html_entity] ||= ""
      cur[:decimal_mark] = curr["separator"]
      cur[:thousands_separator] = curr["delimiter"]
      cur
    end
end

A few attributes in my Currency implementation are non-standard - and my 'base' model do sneaky stuff - but all that is irrelevant :)

@weppos
Owner

@alup @semmons99 I agree with the path you are taking.

My suggestion about having currencies and other stuff being loaded from a database, is to design an API to allow this so that the interface is there, then ship the library a default adapter that implements that interface and loads currencies from the default source.

Users will be able to create and assign their own adapters. More or less what we did with the Bank feature in Money.

We might probably want to add this abstraction to money and money-rails will simply ship a new AR adapter that implements the default interface.

@semmons99 semmons99 closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.