Я работаю над очень простой системой корзины покупок.
У меня есть таблица items
, у которой есть столбец price
типа integer
.
У меня возникли проблемы с отображением цены в моих прогнозах по ценам, которые включают как евро, так и центы. Я пропустил что-то очевидное, касающееся обработки валюты в структуре Rails?
Вероятно, вы захотите использовать тип DECIMAL
в своей базе данных. В вашей миграции выполните следующие действия:
# precision is the total number of digits
# scale is the number of digits to the right of the decimal point
add_column :items, :price, :decimal, :precision => 8, :scale => 2
В Rails тип :decimal
возвращается как BigDecimal
, что отлично подходит для расчета цены.
Если вы настаиваете на использовании целых чисел, вам придется вручную конвертировать в и из BigDecimal
всюду, что, вероятно, просто станет болью.
Как указано mcl, для печати цены используйте:
number_to_currency(price, :unit => "€")
#=> €1,234.01
item.price
возвращает «12,5» вместо «12,50» ...
Здесь тонкий простой подход, который использует composed_of
(часть ActiveRecord, используя шаблон ValueObject) и денежный камень
Вам понадобится
Product
integer
в вашей модели (и базе данных), например :price
Запишите это в свой product.rb
файл:
class Product > ActiveRecord::Base
composed_of :price,
:class_name => 'Money',
:mapping => %w(price cents),
:converter => Proc.new { |value| Money.new(value) }
# ...
Что вы получите:
product.price = "$12.00"
автоматически преобразуется в класс Moneyproduct.price.to_s
отображает десятичное форматированное число ( "1234.00" )product.price.format
отображает правильно отформатированную строку для валютыproduct.price.cents.to_s
Обычная практика обработки валюты - использовать десятичный тип. Вот простой пример из "Agile Web Development with Rails"
add_column :products, :price, :decimal, :precision => 8, :scale => 2
Это позволит вам обрабатывать цены от -999,999,99 до 999,999.99
Вы также можете включить проверку в свои элементы, например
def validate
errors.add(:price, "should be at least 0.01") if price.nil? || price < 0.01
end
чтобы проверить работоспособность.
Используйте драгоценный камень с денежными рельсами. Он прекрасно обрабатывает деньги и валюты в вашей модели, а также имеет кучу помощников для форматирования ваших цен.
Используя Виртуальные атрибуты (ссылка на пересмотренный (платный) Railscast), вы можете сохранить свои price_in_cents в целочисленном столбце и добавить виртуальный атрибут price_in_dollars в свою модель продукта как геттер и сеттер.
# Add a price_in_cents integer column
$ rails g migration add_price_in_cents_to_products price_in_cents:integer
# Use virtual attributes in your Product model
# app/models/product.rb
def price_in_dollars
price_in_cents.to_d/100 if price_in_cents
end
def price_in_dollars=(dollars)
self.price_in_cents = dollars.to_d*100 if dollars.present?
end
Источник: RailsCasts # 016: Виртуальные атрибуты: Виртуальные атрибуты - это чистый способ добавления полей формы, которые не отображаются непосредственно на база данных. Здесь я покажу, как обрабатывать проверки, ассоциации и т.д.
Если вы используете Postgres (и с тех пор, как мы сейчас в 2017 году), вы можете попробовать попробовать их тип столбца :money
.
add_column :products, :price, :money, default: 0
Я использую его следующим образом:
number_to_currency(amount, unit: '€', precision: 2, format: "%u %n")
Конечно, символ валюты, точность, формат и т.д. зависят от каждой валюты.
Если кто-то использует Sequel, миграция будет выглядеть примерно так:
add_column :products, :price, "decimal(8,2)"
каким-то образом Sequel игнорирует: точность и масштабирование
(Продолжение версии: продолжение (3.39.0, 3.38.0))
Определенно целые числа.
И даже несмотря на то, что BigDecimal технически существует 1.5
, он все равно даст вам чистый Float в Ruby.
Мои базовые API-интерфейсы использовали котировки для представления денег, и я не хотел их менять. Я тоже не работал с большими деньгами. Поэтому я просто помещаю это в вспомогательный метод:
sprintf("%03d", amount).insert(-3, ".")
Это преобразует целое число в строку с по меньшей мере тремя цифрами (при необходимости добавляет ведущие нули), затем вставляет десятичную точку перед двумя последними цифрами, никогда не используя Float
. Оттуда вы можете добавить любые символы валюты, подходящие для вашего прецедента.
Это определенно быстро и грязно, но иногда это просто отлично!
Вы можете передать некоторые параметры number_to_currency
(стандартный помощник представления Rails 4):
number_to_currency(12.0, :precision => 2)
# => "$12.00"
Как отправлено Дилан Марков
Простой код для Ruby и Rails
<%= number_to_currency(1234567890.50) %>
OUT PUT => $1,234,567,890.50
DECIMAL(19, 4)
является популярным выбором проверить это также проверить здесь мировую валюту форматы , чтобы решить , сколько знаков после запятой для использования, надежда помогает.