237

Is there a way to have rails print out a number with commas in it?

For example, if I have a number 54000000.34, I can run <%= number.function %>, which would print out "54,000,000.34"

thanks!

Promise Preston
  • 24,334
  • 12
  • 145
  • 143
Jess
  • 3,111
  • 3
  • 22
  • 17

16 Answers16

394

You want the number_with_delimiter method. For example:

<%= number_with_delimiter(@number, :delimiter => ',') %>

Alternatively, you can use the number_with_precision method to ensure that the number is always displayed with two decimal places of precision:

<%= number_with_precision(@number, :precision => 2, :delimiter => ',') %>
John Topley
  • 113,588
  • 46
  • 195
  • 237
  • Can this be used in a helper i.e module? or is it just for views? is there a equivalent method for a moudle? thanks – Mo. Jul 21 '10 at 16:21
  • 6
    @Mo It's a view helper method. You should be able to use it from a module by including `ActionView::Helpers::NumberHelper` within the module. – John Topley Jul 22 '10 at 07:55
  • 9
    I believe by default the delimiter is a comma so you wouldn't need to pass in that option in this case. – Deekor Oct 16 '13 at 07:38
  • 3
    You should leave the delimiter off so that the current locale can decide what to use. This allows locales that use periods for delimiters to be displayed properly rather than putting what they would consider a decimal point between thousands. See coloradoblue answer below. – Kyle Heironimus Dec 16 '13 at 14:13
  • 2
    Rails 4 syntax: <%= number_with_precision(@number, precision: 0, delimiter: ',') %> – Choylton B. Higginbottom May 23 '15 at 21:27
  • I think you mean ruby 1.9, not rails 4, @meetalexjohnson – Robin Aug 10 '17 at 18:31
  • 6
    Beware: `number_with_delimiter` is overly-complex and really slow, with enormous depths of call stacks. It uses `i18n` to be able to format any numbers known to humanity and extraterrestrial civilizations (or maybe just to choose either `,` or `.` for decimal digits, even if you specify it as argument). It allocates thousands of objects (so its performance patterns are complex and hard to profile). Consider just using regexps if you don't need to support different ways to format numbers depending on locale. – kolen Dec 11 '18 at 13:06
  • @kolen I must agree. We were getting some performance hits and methods from the NumberHelper were the root cause. – Gyfis Aug 06 '19 at 11:09
  • `number_with_precision` was perfect for my use. Thank you! – aronmoshe_m Feb 27 '21 at 17:17
  • seconding the call to beware `number_with_delimiter`'s performance -- I was using it in a large financial report and it ate up at least two-thirds of the rendering time. – johncip Feb 09 '23 at 04:31
154

For anyone not using rails:

number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
pguardiario
  • 53,827
  • 19
  • 119
  • 159
  • 2
    Nice. And your answer seems to be *minutely* (only a fraction of a second over one million iterations) faster than the approach presented [here](http://www.rubyquiz.com/quiz113.html): `number.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(',').reverse` – user664833 Dec 31 '12 at 22:21
  • can you explain what is going on here? number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse – Stephen Nguyen Feb 21 '13 at 23:37
  • 7
    Sure, it reverses the string, then adds a comma after any sequence of 3 digits that is also followed by another digit, then reverses it back. – pguardiario Feb 22 '13 at 00:04
  • @pguardiario - I just tried it in irb. 2051851.1542541 turns into 2,051,851.1,542,541 – renosis Mar 10 '13 at 20:30
  • 1
    @renosis - I see what you mean now, this is for formatting currency. So 2 decimals, not 7. – pguardiario Mar 10 '13 at 22:32
  • @pguardiario - it is not like it is a big deal, I still used it in my code. All I did was only apply it to the whole number part. – renosis Mar 11 '13 at 02:24
  • 2
    @pguardiario What's the extra \ for in the \\1? isn't `\1` sufficient? Thanks. – butterywombat Oct 07 '14 at 02:25
  • Yes, `\1` is sufficient – pguardiario Oct 07 '14 at 02:50
  • the double reverse is not necessary. you can do something like what fxfilmxf did in [another answer](http://stackoverflow.com/a/18884577/2544629). – manroe Oct 06 '15 at 23:19
  • @renosis With decimals it becomes `number.to_s.reverse.gsub(/(\d+\.)?(\d{3})(?=\d)/, '\\1\\2,').reverse` – Dan Apr 17 '16 at 18:57
  • @renosis or you could use a dedicated library, as suggested in [this answer](https://stackoverflow.com/a/41431659/6320039) – Ulysse BN Sep 27 '19 at 08:19
66

The direct way to do this, with or without Rails, is:

require 'active_support'
require 'active_support/core_ext/numeric/conversions'

123456.to_fs(:delimited)     # => "123,456"
123456.789.to_fs(:delimited) # => "123,456.789"

For more options, see Active Support Core Extensions - Numeric - Formatting.

chocolateboy
  • 1,693
  • 1
  • 19
  • 21
  • 2
    And with this inclusion you can use `ActiveSupport::NumberHelper.number_to_delimited` as well. This answer deserve a lot more upvotes. – Ulysse BN Sep 30 '19 at 08:31
  • I'm getting uninitialized constant ActiveSupport::Autoload (NameError) – Cruz Nunez Apr 10 '21 at 16:08
  • @CruzNunez If it's not already loaded, you'll need to [`require "active_support"`](https://guides.rubyonrails.org/active_support_core_extensions.html#how-to-load-core-extensions) first. I've updated the answer. – chocolateboy May 13 '21 at 16:41
  • You make the assumption that `active_support` is installed, which would be the case for the OP. Careful not to assume it should be done this way for all Ruby non-Rails code. – lacostenycoder Nov 04 '21 at 20:01
  • you can also hav a custom delimiter and separator ```ruby 12345678901.234.to_s(:delimited, delimiter: " ", separator: ":") => "12 345 678 901:234" ``` – Michael Milewski Jan 27 '22 at 01:50
  • 2
    I guess this changed in some version, but it seems like this should be .to_fs(:delimited) now. – kodbuse Mar 30 '22 at 05:06
32

Yes, use the NumberHelper. The method you are looking for is number_with_delimiter.

 number_with_delimiter(98765432.98, :delimiter => ",", :separator => ".")
 # => 98,765,432.98
Pesto
  • 23,810
  • 2
  • 71
  • 76
PatrikAkerstrand
  • 45,315
  • 11
  • 79
  • 94
31

If you want to add commas outside of views and you don't want to include some modules, you can use number_to_delimited method (rails version >= 4.02). For example:

#inside anywhere
ActiveSupport::NumberHelper.number_to_delimited(1000000) # => "1,000,000"
21

If you're doing it a lot but also FYI because it's not implied by the above, Rails has sensible defaults for the number_with_delimiter method.

#inside controller or view
number_with_delimiter(2444323.4)
#=> 2,444,323.30

#inside console
helper.number_with_delimiter(233423)
#=> 233,423

No need to supply the delimiter value if you're doing it the most typical way.

John Topley
  • 113,588
  • 46
  • 195
  • 237
coloradoblue
  • 625
  • 7
  • 11
  • This has the added benefit of using the current locale. This is really important in international apps since some locales use comma for decimal and period for thousands separator. – Kyle Heironimus Dec 16 '13 at 14:11
19

A better way for those not using rails that handles decimals:

parts = number.to_s.split('.')
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
parts.join('.')

If you want a different delimiter, change the last ',' in the regex.

For bonus, this is how the regex is working:

  • gsub replaces everything that matches the regex with the second parameter passed to gsub. In this case that is \\1. \\1 becomes \1 when evaluated which matches the first capture group in the regex. In this regex that is (\d).
  • (\d)(?=(\d\d\d)+) is matching a digit followed by 1 or more groups of 3 digits. The first set of parens is our \1 capture group, the second would be \2. If we were just to leave it at that we would get: 123456.gsub!(/(\d)(?=(\d\d\d)+)/, "\\1,") #=> 1,2,3,456 This is because 1234 matches, 2345 matches and 3456 matches so we put a comma after the 1, the 2, and the 3.
  • By adding the (?!\d) we are matching anything that comes before that doesn't precede a digit so (\d)(?=(\d\d\d)+(?!\d)) means match a digit followed by 3 digits that is not followed by a digit. The reason why this works is that gsub will keep replacing things that match the string. If we were only going to replace the first match then for a number like 123456789 we would get 123456,789. Since 123456,789 still matches our regex we get 123,456,789.

Here is where I got the code: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/number_helper.rb#L298-L300

And here is where I learned about what is going on in that regex: http://www.tutorialspoint.com/ruby/ruby_regular_expressions.htm

fxfilmxf
  • 582
  • 6
  • 13
  • works like a charm, especially in Liquid template lang: `{{ value | round | replace: "(\d)(?=(\d\d\d)+(?!\d))", "$1," | prepend: "$" }}` – Kukunin Oct 08 '19 at 08:20
2

new syntax

number_with_delimiter(@number, delimiter: ",")

If you you want to user delimeter for money then you can do

number_to_currency(@number)

this will add $ too. If you are using money gem then you can do

Money.new(@number,"USD").format

This will also put $.

number_with_delimiter

ruby money

number_to_currency

Sam Soffes
  • 14,831
  • 9
  • 76
  • 80
gsumk
  • 809
  • 10
  • 15
2

I had this challenge when working on a Rails 6 application.

If the number is for the price of an item or has to do with currency, then you can use number_to_currency ActionView Helper

Here's how to do it:

number_to_currency("123456789")                      # => $123456789
number_to_currency(1234567890.50)                    # => $1,234,567,890.50
number_to_currency(1234567890.506)                   # => $1,234,567,890.51
number_to_currency(1234567890.506, precision: 3)     # => $1,234,567,890.506
number_to_currency(1234567890.506, locale: :fr)      # => 1 234 567 890,51 €
number_to_currency(1234567890.50, unit: '₦', delimiter: ',', precision: 0)    # => ₦1,234,567,890
number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "")  # => R$1234567890,50

You can read up more about it here in the Rails documentation: number_to_currency

That's all.

I hope this helps

Promise Preston
  • 24,334
  • 12
  • 145
  • 143
2

For Ruby guys: Formatting numbers (integers only) with a comma separator between every group of thousands.

number = 12345678
numStr1 = number.to_s.reverse.scan(/.{1,3}/).join(',').reverse
puts numStr1             # => 12,345,678

numStr2 = number.to_s.gsub(/\B(?=(...)*\b)/, ',')
puts numStr2             # => 12,345,678
  • The `number.to_s.reverse.scan(/.{1,3}/)` piece seems like a good place to start if you wanted to produce output like 4.32M or 12.3G. The top two array entries could be joined with "." and then trimmed to the length you want, reverse, and add the suffix based upon the length of the array `scan` produced. – pedz May 18 '22 at 14:43
1

You can use methods from ActiveSupport

For example:

ActiveSupport::NumberHelper::number_to_currency(10000.1234,{precision: 2,unit: ''})

Le Duc Duy
  • 1,881
  • 1
  • 19
  • 18
1

Another solution that does not use Helpers: format with 2 decimal places, and then replace . by ,

puts(("%.2f" % 2.5666).gsub('.',','))
>> 2,57
Nino van Hooff
  • 3,677
  • 1
  • 36
  • 52
  • 3
    I believe the question was about commas for [digit grouping](https://en.wikipedia.org/wiki/Decimal_separator#Digit_grouping), not comma as intergral part/fraction part decimal separator that your answer achieves. (as that wiki link explains, due to the long-standing confusion, internetional standards now recommend spaces only for digit grouping) – Beni Cherniavsky-Paskin Feb 14 '18 at 09:13
1
  def add_commas(numstring)
    correct_idxs = (1..100).to_a.select{|n| n % 6 == 0}.map{|n| n - 1}
     numstring.reverse.chars.join(",").chars.select.with_index{|x, i| i.even? || correct_idxs.include?(i)}.join.reverse
  end

This was my way in ruby

Addition edit: Basically it adds all commas in between the numbers and only selects the ones where the index + 1 % 6

I figured the commas up to 100 was fine but if you want a super long number just make 100 a higher number

Justin Cox
  • 21
  • 2
1

The following do the trick for both delimiter and precision (API ref).

ActiveSupport::NumberHelper.number_to_rounded(1234.532, delimiter: ',', precision: 1) 
     

(or from views just number_to_rounded, no need for the prefix)

HTH

Hertzel Guinness
  • 5,912
  • 3
  • 38
  • 43
0

For Ruby Folks: functions can be created to set comma to large number integer.

def number_with_comma(numStr)
   return numStr.to_s.gsub(/\B(?=(...)*\b)/, ',')
end
a = number_with_comma 1234567
puts a   => 1,234,567

x = 9876543
y = number_with_comma x
puts y   => 9,876,543
-1

for javascript folks

function numberWithDelimiter(value) {
    return (value+"").split("").reverse().join("").replace(/(\d{3})(?=\d)/g, '$1,').split("").reverse().join("")
}

:)

aqm
  • 2,942
  • 23
  • 30