bookmark_borderRailsCollab on Rails 2.0

Soon after hearing that version 2.0 of the Ruby on Rails web development framework had been released, I decided to try out my pet project RailsCollab to see if it would work properly in the new release.

Sadly it did not, though it didn’t take too long to fix everything. To summarise:

  1. I still used a few deprecated functions and parameters, such as link_to_url, @request, start_form_tag, and so on. Changing references to their new counterparts solved this issue.
  2. Two plugins I use, “enum-column” and “paginating_find” broke. I had to modify the code for these as illustrated below.
  3. A new script, “script/performance/request” was added to I naturally had to add it to my svn repository
  4. The default session container changed to cookies, so I had to fill in “config.action_controller.session” in config/environment.rb
  5. “config.breakpoint_server = true” had to be removed from my development environment
  6. Mongrel decided to through a wobbler and stop working, so I had to do a reinstall of it

How to update

Initially I was a bit confused regarding the correct update procedure, however I believe the following commands should suffice:

sudo gem update rails -y

# In your app's directory
rake rails:update

enum-column fix

Since database plugins for Rails have been seperated from the core, enum-column runs into a bit of trouble as it assumes the plugins for MySQL and PostgreSQL are loaded when in most cases they are not.

In addition I couldn’t even get the PostgreSQL plugin working, though this wasn’t so much an issue as I only use the plugin to support the initial database schema from ActiveCollab.

So in “vendor/plugins/enum-column/plugins/enum-column/init.rb”, change the following:

require 'enum/mysql_adapter'
require 'enum/postgresql_adapter'

To this:

require 'enum/mysql_adapter' if (ActiveRecord::ConnectionAdapters.const_defined? :MysqlAdapter)
# require 'enum/postgresql_adapter'

paginating_find fix

This one is rather simple. In “vendor/plugins/paginating_find/lib/paginating_find.rb”, look for this line:

options = extract_options_from_args!(args)

And change it to this:

options = args.extract_options!

Initial impressions

I was very impressed to find that RailsCollab was notably faster in development mode. I suspect this is due to a combination of that fancy query caching system and of course the change to cookie-based storage as the default session storage system.

Apart from the minor hiccups I had when updating RailsCollab, i’ve not had any more issues with Rails 2.0. For my future projects, I will definitely be targeting Rails 2.0.

bookmark_borderDouble Entry Accounting in Rails

The first helpful article I found, Double Entry Accounting in a Relational Database, suggests I need at least the following models in my system:

  • Account (has many Postings)
  • Asset Type (e.g. £, $, monkeys)
  • Batch (has many Journals, though not really needed)
  • Journal (has many Postings)
  • Posting (associates with Account, Journal, and Asset Type)

However one problem I noticed with the article was that instead of separate “credit” and “debit” fields, everything is consolidated into an “amount” field. This meant that the abstraction between debiting and crediting needed to be handled in the model rather than the actual database.

Puzzled by this, I decided to look at the database schema used in other Accounting products: LedgerSMB and jGnash.

LedgerSMB Logo

LedgerSMB uses a rather complex database schema. I couldn’t make much sense of it, apart from like the aforementioned article it consolidated credits and debits into an “amount” field rather than have them as separate fields.

jGnash Logo

jGnash was a bit different as instead of a proper database it uses an XML file to store its data. Still, there were a few distinctive elements which are the equivalent of models:

  • Account (linked to Transaction and CurrencyNode)
  • SingleEntryTransaction (linked to Account, used to insert money out of thin air)
  • DoubleEntryTransaction (linked to 2 Accounts ‘credit’ and ‘debit’. Also links with CurrencyNode)
  • SplitTransaction (used to link multiple SplitEntryTransaction’s together to indicate a split transaction)
  • SplitEntryTransaction (linked to SplitTransaction, otherwise the same as DoubleEntryTransaction)
  • CurrencyNode (e.g. £, $, giraffes)

Personally I found jGnash’s XML format needlessly complicated, though much more comprehensible than LedgerSMB’s database schema.

Though really, the approach I liked the best was the one mentioned in the article. It made the most sense, and wasn’t needlessly complicated. So I decided to implement it.

While implementing it however, I became a bit stuck on how to abstract the credit and debit in the Posting entries.

Whenever I have looked at Double Entry Accounting in the past, I always assumed that when you take money out of one account, you need to put the same amount back into another account. Thus I made this rather mistaken test data:

# Begin asset types

gbp = => 'GBP', :symbol => '£')!

# Begin accounts

assets = => nil,
:asset_type => gbp,
:name => 'Assets',
:account_type => :asset)!
equipment = => assets,
:asset_type => gbp,
:name => 'Equipment',
:account_type => :asset)!

liabilities = => nil,
:asset_type => gbp,
:name => 'Liabilities',
:account_type => :liability)!
fred = => liabilities,
:asset_type => gbp,
:name => 'Fred',
:account_type => :liability)!
george = => liabilities,
:asset_type => gbp,
:name => 'George',
:account_type => :liability)!

# Begin transactions

first_transaction = => :transfer, :start_date =>! => george,
:asset_type => gbp,
:journal => first_transaction,
:account_period => 0,
:description => 'Funding',
:amount => -250.00).save! => equipment,
:asset_type => gbp,
:journal => first_transaction,
:account_period => 0,
:description => 'Funding',
:amount => +250.00).save!
first_transaction.end_date =!

second_transaction = => :transfer, :start_date =>! => equipment,
:asset_type => gbp,
:journal => second_transaction,
:account_period => 0,
:description => 'Payback',
:amount => -100.00).save! => george,
:asset_type => gbp,
:journal => second_transaction,
:account_period => 0,
:description => 'Payback',
:amount => +100.00).save!
second_transaction.end_date =!

third_transaction = => :transfer, :start_date =>! => fred,
:asset_type => gbp,
:journal => third_transaction,
:account_period => 0,
:description => 'Investment',
:amount => -300.00).save! => equipment,
:asset_type => gbp,
:journal => third_transaction,
:account_period => 0,
:description => 'Investment',
:amount => +300.00).save!
third_transaction.end_date =!

Which actually appeared to work fine (as in everything sum’d to 0, and if I ignored the minus then Assets = Liabilities) before I started to delve into what debiting and crediting means in relation to whether or not an account is classed as an Asset or a Liability.

(Note that to simplify things when I say Asset I could alternatively be meaning Expenses, and when I say Liability I could alternatively be meaning Shareholder Equity or Revenue)

Account Debit Credit
Assets +
Expenses + (-)
Liabilities +
Shareholder Equity +
Revenue (-) +

After applying the logic from the above table (courtesy of Wikipedia), I noticed something rather odd. The credit and debit columns on my printout didn’t match. For reference, I was using the following queries to grab the credit and debit amounts for each account.:

credit_amount = Posting.sum(:amount, :conditions => "amount #{account_type == :asset ? '<' : '>'} 0")
debit_amount = Posting.sum(:amount, :conditions => "amount #{account_type == :asset ? '>' : '<'} 0")

However if I modified the code slightly:

credit_amount = Posting.sum(:amount, :conditions => "amount < 0")
debit_amount = Posting.sum(:amount, :conditions => "amount > 0")

The credit and debit columns mysteriously matched. So what happened?

Well I puzzled over this for a while, until I read Wikipedia’s article on Double Entry Accounting again. This rather simple summary was very insightful:

Purchase of a Computer

  • Debit Computer A/c (Fixed Asset A/c)
  • Credit Creditors A/c (Liability A/c)

(A/c being an abbreviation of “account current”)

Paying supplier for the computer

  • Debit Creditors A/c (Liability A/c) You are reducing a Liability A/c
  • Credit Bank A/c (Asset A/c) Money going Out, an asset account is being reduced

So in fact all the transactions in my test data should have been increasing the amount in the liability accounts rather than decreasing it (and vice versa when paying back).

It makes sense now I think about it. The second approach worked because in effect I flipped the meaning of debit and credit by decreasing the amount in the liability accounts and calling it credit rather than increasing the amount in the liability accounts and calling it credit (and vice versa).

Now I could just go ahead and fix my test data. But then my amounts would cease to sum up to zero, and I would have to run multiple queries (each for debit and credit) to ensure integrity of the data.

Thus what I really need to do is make an attribute in the Posting model which stores and retrieves the correct “amount” depending on what type of account it is. Something like this should suffice:

def real_amount
  return self.account.account_type == :asset ? self.amount : -self.amount

def real_amount=(val)
  self.amount = self.account.account_type == :asset ? val : -val

So to sum it up, the only thing I really have to do with liability accounts to satisfy accounting rules is to subtract when I really mean add, and then flip the balance when calculating it. Confusion eliminated!

Now lets hope I don’t get confused again when I start to think “Did I get this right?”.

Currently I am looking into how I can effectively incorporate business concepts such as Invoices, Taxation, and so on into my little Double Entry Accounting system. So expect to see a “Double Entry Accounting with Invoicing in Rails” post in the near future.