Search code examples
ruby-on-railsrubybigdecimalzeronumber-to-currency

BigDecimal to Currency with -0.0


I am working on reports for a website and I am currently thinking of what would be the best way to handle BigDecimal -0.0's.

The database I'm working with has a lot of them. When these -0.0's are put through number_to_currency(), I get "$-0.00". My format for negative numbers is actually "-$x.xx", so note that number_to_currency is not formatting it as a negative number (otherwise there would also be a negative sign in front of the dollar sign), but for some reason the negative sign is being translated along with the 0.

Right now my solution is to do this every time I get an amount from the database:

amount *= -1 if amount == 0 && amount.sign == -1

This changes the -0.0 to a 0.0. It's simple enough, but I can't help but wonder if there is a better solution, or something on BigDecimals or number_to_currency to handle this situation that I'm just not finding.


Solution

  • That is so because the number is converted into a string to be displayed. And:

    # to_d converts to BigDecimal, just FYI
    "-0".to_d.to_s #=> "-0.0"
    

    Therefore you will have to make it a 0 yourself. But the sign-checks are redundant - a simple comparison with 0 will do the trick:

    bdn = "-0".to_d # or BigDecimal.new("-0")
    value = bdn.zero? ? 0 : bdn
    number_to_currency(value, other_options)
    

    However, you wouldn't want to manually add this check everywhere you're calling number_to_currency. It would be more convenient to create your own modified_number_to_currency method, in your ApplicationHelper, like so:

    def modified_number_to_currency( number, options )
      value = number.zero? ? 0 : number
      number_to_currency(value, options)
    end
    

    And then use modified_number_to_currency instead of number_to_currency.

    Alternatively, you could overwrite number_to_currency and have it call super in the end. That might also work but I'm not 100% certain.

    Coming to your check specifically:

    amount *= -1 if amount == 0 && amount.sign == -1
    

    It should simply be:

    amount = 0.to_d if amount.zero? # the to_d might or might not be required