如果通过关联访问,为什么 BigDecimal 比例会发生变化?
Why does a BigDecimal scale changes if accessed through an association?
我在 Rails 型号 Farm
和 Harvest
上有两个 Ruby。一个农场属于一个收获。以下是型号:
class Farm < ActiveRecord::Base
acts_as_singleton
belongs_to :harvest
validates :harvest, presence: true, allow_blank: true
serialize :harvest_time, Tod::TimeOfDay
validates :harvest_time, presence: true, allow_blank: true
validates :hash_rate, presence: true
validates_with HashRateValidator
end
class Harvest < ActiveRecord::Base
belongs_to :user
validates :user, presence: true
validates :date, presence: true
validates :amount, presence: true
validates :identifier, presence: true
validates :amount, numericality: { :greater_than => 0 }
end
只有一个农场(多亏了单身人士gem)。每次收获完成时,农场的收获关联都会发生变化,因为它总是必须指向最新的收获。由于我将农场用作单例模型,因此我使用以下代码更新农场:
@harvest = Harvest.new(
:date => DateTime.now,
:amount => amount,
:identifier => new_identifier,
:user => current_user,
:assigned => false
)
if @harvest.save
Farm.instance.update_attributes(:harvest => @harvest)
byebug
奇怪的是收获量的值和分配给农场的收获量在这之后不匹配:
(byebug) Farm.instance.harvest.amount
435.435
(byebug) @harvest.amount
435.435345343
(byebug) Farm.instance.harvest.id
12
(byebug) @harvest.id
12
小数点的小数位数应为 8 位,精度为 6 位(来自迁移),这里是 schema.rb 文件的相关部分:
create_table "harvests", force: :cascade do |t|
t.datetime "date"
t.decimal "amount", precision: 6, scale: 8
t.integer "identifier"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
...
end
那么,这是怎么回事?金额应该是完全相同的值!
我明白了。规模和精度没有意义。 Precision 是 BigDecimal 数量上的位数,scale 是出现在小数点右边的那些数字的数量。由于精度设置为 6,因此小数点后无法容纳 8 位数字。因此,当数字来自数据库时,它被截断了,当它来自内存时,它的所有数字都在小数点后。 我通过将精度设置为 18 并将小数位数设置为 8 来修复它,这意味着总共 18 位数字,其中 8 位出现在小数点右侧。
Sqlite 允许不连贯的精度 => 6 和小数位数 => 8。Postgres 不允许。
我在 Rails 型号 Farm
和 Harvest
上有两个 Ruby。一个农场属于一个收获。以下是型号:
class Farm < ActiveRecord::Base
acts_as_singleton
belongs_to :harvest
validates :harvest, presence: true, allow_blank: true
serialize :harvest_time, Tod::TimeOfDay
validates :harvest_time, presence: true, allow_blank: true
validates :hash_rate, presence: true
validates_with HashRateValidator
end
class Harvest < ActiveRecord::Base
belongs_to :user
validates :user, presence: true
validates :date, presence: true
validates :amount, presence: true
validates :identifier, presence: true
validates :amount, numericality: { :greater_than => 0 }
end
只有一个农场(多亏了单身人士gem)。每次收获完成时,农场的收获关联都会发生变化,因为它总是必须指向最新的收获。由于我将农场用作单例模型,因此我使用以下代码更新农场:
@harvest = Harvest.new(
:date => DateTime.now,
:amount => amount,
:identifier => new_identifier,
:user => current_user,
:assigned => false
)
if @harvest.save
Farm.instance.update_attributes(:harvest => @harvest)
byebug
奇怪的是收获量的值和分配给农场的收获量在这之后不匹配:
(byebug) Farm.instance.harvest.amount
435.435
(byebug) @harvest.amount
435.435345343
(byebug) Farm.instance.harvest.id
12
(byebug) @harvest.id
12
小数点的小数位数应为 8 位,精度为 6 位(来自迁移),这里是 schema.rb 文件的相关部分:
create_table "harvests", force: :cascade do |t|
t.datetime "date"
t.decimal "amount", precision: 6, scale: 8
t.integer "identifier"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
...
end
那么,这是怎么回事?金额应该是完全相同的值!
我明白了。规模和精度没有意义。 Precision 是 BigDecimal 数量上的位数,scale 是出现在小数点右边的那些数字的数量。由于精度设置为 6,因此小数点后无法容纳 8 位数字。因此,当数字来自数据库时,它被截断了,当它来自内存时,它的所有数字都在小数点后。 我通过将精度设置为 18 并将小数位数设置为 8 来修复它,这意味着总共 18 位数字,其中 8 位出现在小数点右侧。
Sqlite 允许不连贯的精度 => 6 和小数位数 => 8。Postgres 不允许。