Nathan Long Nathan Long - 4 days ago 4
Ruby Question

Can DataMapper `Decimal` properties to automatically round to the correct scale?

Suppose I have the following DataMapper model:

class Payment
include DataMapper::Resource

property :id, Serial
property :amount, Decimal, precision: 8, scale: 2
end


Then I do the following:

p = Payment.new(:amount => 12.3245)


This payment will be invalid (at least with DataMapper 1.2), saying that
Amount must be a number
.

Of course, amount is a number (shakes fist); it just has more decimal places than the property will accept. If I do
p.amount = p.amount.round(2)
, the payment will be valid.

I could write a setter to take away this annoyance:

def amount=(val)
@amount = val.round(2)
end


...but then I have the annoyance of writing a bunch of identical setters on different models.

I would much prefer to handle this with the same, sensible rule for all
Decimal
properties, system-wide. Namely, since you know your own scale, round to that scale before saving.

Is this something that can be handled with a configuration option, or maybe an initializer?

Answer

You could monkey patch DataMapper's Decimal class (original at dm-core-1.2.0/lib/dm-core/property/decimal.rb):

module DataMapper
  class Property
    class Decimal
      alias :original_typecast_to_primitive :typecast_to_primitive
      def typecast_to_primitive(value)
        typecasted = original_typecast_to_primitive(value)
        typecasted.round(@scale) if typecasted.respond_to?(:round)
      end
    end
  end
end

or you could define you own property type NiceDecimal with the new behavior.

Comments