I am an experienced web developer, but new to rails. I am writing a budget application based on a double-entry accounting database. The database contains journal entries to represent transactions, and each journal entry has multiple postings. Each posting has an account and an amount. I’ve represented a debit amount as a negative amount and a credit amount as a positive amount.
However, I don’t expect the user to remember about positive and negative, so I’ve made virtual attributes for credit amount and debit amount on my model so that the user will see separate credit amount and debit amount fields.
The Posting model is below:
class Posting < ActiveRecord::Base
belongs_to :account
belongs_to :journal_entry
attr_accessible :account_id, :credit_amount, :debit_amount
attr_accessor :credit_amount, :debit_amount
after_validation :set_amount
after_find :split_amount
validates :credit_amount, :format => { :with => /\A(?:\d+(?:\.\d{1,2})?|(?:.\d{1,2}))?\z/ }
validates :debit_amount, :format => { :with => /\A(?:\d+(?:\.\d{1,2})?|(?:.\d{1,2}))?\z/ }
validate :check_amounts
def check_amounts
unless @account_id.blank?
if not @debit_amount.blank? and not @credit_amount.blank?
errors.add(:base, "cannot specify both credit and debit amount.")
elsif @debit_amount.blank? and @credit_amount.blank?
errors.add(:base, "must specify one of credit or debit amount.")
end
end
end
protected
def set_amount
unless @debit_amount.blank? and @credit_amount.blank?
self.amount = @debit_amount.blank? ? BigDecimal.new(@credit_amount) : -BigDecimal.new(@debit_amount)
end
end
def split_amount
@credit_amount = (self.amount.nil? or self.amount >= 0) ? self.amount : nil
@debit_amount = (self.amount.nil? or self.amount >= 0) ? nil : -self.amount
end
end
Is this the right way to use 2 virtual attributes (credit_amount and debit_amount) for the 1 model field (amount)? I tried writing getters and setters for credit_amount/debit_amount that used the underlying amount field directly, but that meant that I couldn’t accurately report validation errors to the user.
I like the way you have written it. The credit amount and debit amount validations using regex are tighter than just validating those fields to be numeric. The split amount method could use a comment above to explain what you are doing there, so that the next guy debugging at 3:00AM doesn’t have to figure it out(actually, the regex could use an explicit description comment too).
I hope this helps.
Good luck!