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

1k views Asked by At

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?

2

There are 2 answers

3
ujifgc On BEST 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.

0
fullstackplus On

Have you considered writing your own DataMapper data types for each of your scale categories? That way, there's no monkey-patching and you can specify as many cases as you want without littering any existing class with if / switch statements. DataMapper has a mechanism for this, see a list of custom data types in the "Available Types" section of the properties docs.