# Supporting fractions in Ruby/Rails

Unicode comes with a selection of common single-character fractions like ½, ¼, and even ⅐ (see en.wikipedia.org/wiki/Number_Forms for more), but I need to store and display somewhat arbitrary fractions in a Rails app and it isn’t something I’ve had to do before so I’m documenting my workings.

Ruby has the `Rational`

class that makes it easy to work with fractions and can perform a specific calculation I need (½ + ⅐ = ⁹⁄₁₄):

```
a = Rational(1, 2)
# => (1/2)
b = Rational(1, 7)
# => (1/7)
a + b
# => (9/14)
```

My numbers are stored in a PostgreSQL database which doesn’t support rationals but fortunately in Ruby any number can be turned into a `Rational`

with `#to_r`

:

```
0.5.to_r
# => (1/2)
```

Unfortunately you don’t often get a sensible fraction:

```
(9.0 / 14).to_r
# => (5790342378047781/9007199254740992)
```

A `Rational`

can be simplified with `Rational#rationalize`

and with a bit of trial and error I determined that to arrive at ⁹⁄₁₄ I need to store the number with 3 decimal places and pass a magic number of ~0.005 to `Rational#rationalize`

:

```
0.643.to_r
# => (2895814560399229/4503599627370496)
0.643.to_r.rationalize(0.1)
# => (2/3)
0.643.to_r.rationalize(0.01)
# => (7/11)
0.643.to_r.rationalize(0.001)
# => (9/14) ✅
# Can I store the number with two decimal places? No.
0.64.to_r.rationalize(0.001)
# => (16/25)
# What magic number do I need?
0.643.to_r.rationalize(0.005)
# => (9/14) ✅
```

Next, I can never remember how to use decimals with Rails/PostgreSQL. The following Rails migration adds a decimal type column that can store numbers up to 999.999 — `precision: 6`

means the number can have total of 6 digits, `scale: 3`

means 3 of those digits come after the decimal point (surely it should be the other way round, scale for how big the number is and precision for its decimal places?):

```
add_column :standings, :points, :decimal, precision: 6, scale: 3
```

Now that I’m storing the number with an appropriate fidelity and can turn it into a sensible fraction I want it to look nice. The following Rails helper method determines if a number is a fraction and formats it with `<sup>`

/`<sub>`

tags:

```
module ApplicationHelper
def fraction(numerator, denominator)
capture do
concat tag.sup(numerator)
concat '⁄' # Unicode fraction slash.
concat tag.sub(denominator)
end
end
def points(number)
return '0' if number.zero?
rational = number.to_r.rationalize(0.005)
whole, remainder = rational.numerator.divmod(rational.denominator)
capture do
concat whole.to_s unless whole.zero?
concat fraction(remainder, rational.denominator) unless remainder.zero?
end
end
end
```

Storing approximate values in the database means you might have to be careful about losing precision, for example ⅐ × 49 = 7 but 0.143 × 49 ≠ 7:

```
BigDecimal('0.143').to_r.rationalize(0.005) * 49
# => (7/1)
BigDecimal('0.143') * 49
# => 0.7007e1
(BigDecimal('0.143') * 49).to_r.rationalize(0.005)
# => (589/84)
```

Luckily I perform limited calculations on my data so this isn’t something I have to worry about.

## Bonus: Unicode fractions

I happened upon a site that demonstrates how to construct fractions from Unicode superscript and subscript characters. Even better is that the source is on GitHub so I borrowed the approach and implemented it in Ruby/Rails:

```
module ApplicationHelper
SUB = %w(₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉)
SUP = %w(⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹)
def fraction(numerator, denominator)
numerator.digits.reverse.map { |char| SUP.fetch(char) }.join \
+ '⁄' \ # Unicode fraction slash.
+ denominator.digits.reverse.map { |char| SUB.fetch(char) }.join
end
end
```