Храните деньги правильно
Для одного из проектов, нам требовалось хранить деньги с копейками, да ещё и с возможностью их отображения в разных валютах с учетом курсов валют.
В ruby для этого используется гем Money.
Однако, у этого гема нет встроенной поддержки Mongoid, поэтому мы сделали свою.
Возможности
Хранение денежных данных с валютой и без валюты:
1 2 |
money_field :price money_field :price2, fixed_currency: 'GBP' |
Поле может быть обязательным и иметь значение по умолчанию:
1 2 3 4 |
# Значение по умолчанию money_field :price3, default: '1.23 RUB' # Обязательное поле money_field :price4, required: true, default_currency: nil |
Парсинг значений, введенных пользователем из форм, с учетом точек, запятых, и всего прочего мусора, который пользователь может ввести в поле ввода цены: $, %, €, руб, Р, р., 12,15руб, 23,123.25 - чего только не вводят пользователи, даже технически грамотные.
Позже Сергей Малых добавил в гем правильную и красивую поддержку валидации через Numeric Validator:
1 2 |
# Валидация поля как числового значения (с поддержкой локализованных десятичных разделителей) validates_numericality_of :price, greater_than: 0 |
Для чего это нужно
Часто встречается, что программисты хранят деньги в БД в виде значений с плавающей точкой (float). Такой подход имеет множество недостатков, начиная от отсутствия данных о валюте, и заканчивая потерей точности данных и проблем округления при арифметических операциях с суммой денег.
А проще
Если вы храните деньги неправильно, Ваша бухгалтерия может быть очень удивлена и недовольна, узнав что 10 раз по 10 копеек это вовсе не рубль, а 99 копеек, или что если из 1 рубля 03 коп вычесть 42 коп, вовсе не получится 61 копейка.