We are using money-rails
gem in our application. Until now, we were OK with 4 decimal digits precision, but we need to switch to 6. Unfortunately I'm unable to store higher precision numbers into Postgres - number is rounded before saving.
class MyModel < ApplicationRecord
monetize :price_cents # :price_cents, :decimal, default: 0, precision: 30, scale: 10
end
Money itself seems to work fine with higher precision
pry(main)> Money.new(181.123456789).to_f
=> 1.81123456789
Testing model in console. All works fine before save.
my_model = MyModel.find(1)
my_model.price = Money.new(181.123456789)
my_model.price.to_f # => 1.81123456789
my_model.save
my_model.price.to_f # => 1.8112
And the ActiveRecord output says the trimmed number is actually being send to database. (notice the 181.12).
UPDATE "my_models" SET "price_cents" = $1 ... [["price_cents", "181.12"] ...]
Is there any way to allow money-rails
gem to work with more precision? It seems like Money gem has no problem with higher precision on its own.
That behavior comes from money rounding, to turn it off, use:
Money.infinite_precision = true
here's test:
require "bundler/inline"
gemfile(ENV['INSTALL']=='1') do
source "https://rubygems.org"
gem "rails", '~>6.0'
gem "sqlite3"
gem 'money-rails'
end
require "minitest/autorun"
require "logger"
require "active_record"
require 'money-rails'
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Schema.define do
create_table(:models, force: true){|t| t.decimal :price_cents, default: 0, precision: 30, scale: 10 }
end
# to remove config warnings:
Money.locale_backend = :currency
Money.default_currency= :usd
# actual fix:
Money.infinite_precision = true
MoneyRails::Hooks.init # in a normal app is called automatically
class Model < ActiveRecord::Base
monetize :price_cents
end
class BugTest < Minitest::Test
def test_association_stuff
m = Model.create!(price_cents: 181.123456789).reload
assert_equal 181.123456789, m.price_cents
assert_equal 1.81123456789, m.price.to_f
m2 = Model.create(price: Money.new(182.123456789)).reload
assert_equal 1.82123456789, m2.price.to_f
end
end