The objective is to use ActiveRecord methods like #where
and #first_or_create
to properly compare a database-persisted BigDecimal value against a Float or String value.
create_things migration:
t.decimal :position, :precision => 10, :scale => 4
relevant code:
position = "0.309624"
thing = Thing.where(:position => position).first_or_create
thing2 = Thing.where(:position => position).first_or_initialize
the issue:
I'm expecting Thing.count
to equal 1 and thing2.persisted?
to be true
, meaning Active Record was able to properly compare position
with thing.position
to find the first record and assign it to thing2
.
debugging:
thing.position #> #<BigDecimal:7ffbdabe42a8,'0.309624E0',9(18)>
thing.position == position #> false
it's possible to do a valid comparison by converting both variables...
thing.position.to_s == position#> true
thing.position.to_f == position.to_f #> true
... but this requires a conversion of the database-persisted value. Is there a way to make this happen using #where
and/or #first_or_create
?
see also How can I compare a BigDecimal with ActiveRecord decimal field?
edit: this question is different from the related question in that the accepted solution to the related question advocates rounding a float, which applied to this example would call for an assignment of position = "0.309624".to_f.round(4)
, which still produces an invalid comparison.
I think I found the answer, which is to convert the position to BigDecimal before comparison:
position = BigDecimal.new("0.309624", 4) # where 4 is the decimal scale.
It seems so simple now...
edit: the BigDecimal also needs to be rounded before storing in the database and when comparing against database value:
position = BigDecimal.new("0.309624", 4).round(4)