user1978591
user1978591

Reputation: 229

Rails 3 AR represents a decimal field as integer

I've already done this without any issue, but today I cannot get it working.

I have a migration as follows

class AddAmountToInvoices < ActiveRecord::Migration
  def change
    add_column :invoices, :amount, :decimal, :precision => 2
  end
end

But then when I set a BigDecimal value the decimal part get the decimal part ignored. By looking at the Invoice model inside the rails console I can see it is declaring :amount as a integer as you can see:

 => Invoice(id: integer, invoice_number: integer, brogliaccio_id: string, kind: string, tax_id: string, payment_method: string, openmanager_user_id: string, created_at: datetime, updated_at: datetime, event_id: integer, amount: integer)

This is the invoice.rb model:

# encoding: utf-8
class Invoice < ActiveRecord::Base
  belongs_to :event

  KINDS = ["Detrazione", "Non Detrazione"]
  TAX_IDS = {"4%" => "004", "10%" => "010", "22%" => "022"}
  PAYMENT_METHODS = {"Bonifico" => "BB", "Contanti" => "CO", "Finanziamento" => "FI", "Assegno" => "AS"}

  attr_accessor :amount_string # we need this to handle custom number-format

  attr_accessible :amount_string, :brogliaccio_id, :invoice_number, :kind, :openmanager_user_id, :payment_method, :tax_id, :amount

  validates_presence_of :amount, :kind, :payment_method, :tax_id, :openmanager_user_id
  validates_inclusion_of :kind, :in => Invoice::KINDS
  validates_inclusion_of :tax_id, :in => Invoice::TAX_IDS.values()
  validates_inclusion_of :payment_method, :in => Invoice::PAYMENT_METHODS.values()
  validate :minimum_amount

  # we get a string formatted as "10.000,50" that needs to be converted to "10000.50"
  # to assure it will be correctly interpretated
  def amount_string=(value)
    value = value.gsub(/\./, '').gsub(/,/, '.')
    self.amount = BigDecimal.new(value, 2)
  end

  def amount_string
    self.amount
  end

  private
  def minimum_amount
    unless self.amount.blank?
      if self.amount < BigDecimal.new("10.0")
        errors.add(:base, "min invoice amount must be 10$")
      end
    end
  end

end

What am I doing wrong here?

Upvotes: 0

Views: 152

Answers (1)

Iralution
Iralution

Reputation: 480

As described here (link) you should use :scale instead of :precision (or both). Precision is for the number of relevant digits, so if you set it to 2 you have 2 relevant digits like 10 or 12 or 1.2 or 0.3 and so on.

"For clarity’s sake: the precision is the number of significant digits, while the scale is the number of digits that can be stored following the decimal point. For example, the number 123.45 has a precision of 5 and a scale of 2. A decimal with a precision of 5 and a scale of 2 can range from -999.99 to 999.99."

So if you want to have an Amount with two digits after the . the migration should look like the following:

class AddAmountToInvoices < ActiveRecord::Migration
    def change
        add_column :invoices, :amount, :decimal, :scale => 2
    end
end

Upvotes: 1

Related Questions