So I’ve been working on a new Rails application, iCash. Actually I’ve make numerous attempts at writing a web based accounting system. Most of them were just reporting (read only a GnuCash sqlite3 file). This one steals GnuCash concepts and reads and writes i.e, i’m thinking of getting rid of GnuCash and all the save-as copy restart, etc. to do the reporting.

It may not go anywhere, like most of my stuff - it just keeps me busy, but it has progressed further than I though. Now in cleanup and putting bells and whistles on it.

Same simple concept:

  class Account < ApplicationRecord
    attribute :transfer
    has_many :splits
    has_many :entries, through: :splits
  end

  class Entry < ApplicationRecord
    has_many :splits, dependent: :destroy, inverse_of: :entry
    validate  :balanced?
    accepts_nested_attributes_for :splits, 
      :reject_if =>  proc { |att| att['debits'].blank? && att['credit'].blank?  && att['account_id'].to_i.zero?},
      allow_destroy: true
  end

  class Split < ApplicationRecord
    belongs_to :entry, inverse_of: :splits
    belongs_to :account
    attribute :debit, :integer
    attribute :credit, :integer
  end

Your have an account list (a hierarchical tree ) as the main index page. That has links to Accounts which go to the show page. The show page is basically a general ledger. From there you can do all the CRUD stuff. Add new Entries, edit, delete, clear, balance, etc, etc.

So Bells and Whistles caused me about 10 hours of wasted time doing something I’ve done a hundred times - Refreshing part of the ledger with an ajax call (.e.g, get a ledger for a different month, date range). Now it has probably been over a year since I so I had to go find an example and more or less clone it.

The main reason for the ajax refresh is that I have a date picker that defines the range of dates to look for. That would be accessed by a select tag that on change would call a JS event.

$('[data-behavior="select_data_url"]').change (e) ->
  tag = $(this)
  url = this.value
  if url.includes("fromto=1")
    # console.log "got a custom date"
    from_date = $('#from_date').val()
    to_date = $('#to_date').val()
    if from_date is ''
      alert "From date is Empty"
      return false
    if to_date is ''
      alert "To date is Empty"
      return false
    url = url.replace('fromto=1',"from=#{from_date}&to=#{to_date}")

  location.assign(url)

Yeah, should change it to an on event, but okay for now. Figured the only thing I had to do was change the last line to an ajax call.

url = url.replace('?','.js?')

$.ajax
    url: url

Then had to add a ‘show.js.erb’ file that the account controller would call for a .js format.

$('#ledger').html('<%= escape_javascript(render partial: "accounts/ledger",locals:{from:@from,to:@to,account:@account}) %>');

Damn thing would not work. I added debugging and all kinds of thing but it just would not work. I could see all the actions taking place in the console, rendering stuff and no errors, but the ledger did not change! Went to half sleep and got up about 4 and tried again with more debugging. Lots of ‘Why?’ on console and rails debugging.

About 5, it hit me!!! I was replacing the #ledger html with the call. For some strange reason (probably copy and paste) I had the ledger div id as ‘Ledger’ instead of ‘ledger’. Boom! It worked and I was happy.

But happiness does not last long.

In the default ledger display, lets say the checking account, all Entries with more that two splits displays the Entry description as a ‘–Split Transaction–’ link, which clicking will open up the split rows. Worked fine until I refreshed the ledger with an ajax call.

Now this is nothing new with jquery UJS, just have to do the right event binding.

$('#ledger').on "click",".toggle-splits", (e) ->

# instead of 
$('#ledger .toggle-splits').click (e) ->

I tried to open a split and it would not open. Another couple of hours of searching my archives and goggling the problem I found the problem and possible solution. That’s why I’m writing this post, so I don’t have to look then copy and paste.

The original Coffee code for clicking the split link was

$('.toggle-splits').on 'click', (e) ->
  td = $(this)
  tb = td.closest('tbody').next().toggle()

Which was pretty bad to begin with, since it searched the entire DOM. so I changed it to

$('#Ledger').on "click",".toggle-splits", (e) ->
  td = $(this)
  tb = td.closest('tbody').next().toggle()

Damn thing didn’t work (notice the uppercase Ledger was used). After more searching, I found a comment on a problem that was the solution, not an answer. Most answers where the same as what I had.

The problem is that I replaced #Ledger with the new ledger, that wiped out all UJS that was based on #Ledger. What I had to do was start from something that was not replaced. I just added a #ajax id to the parent of #Ledger and all worked.

$('#ajax').on "click",".toggle-splits", (e) ->
  td = $(this)
  tb = td.closest('tbody').next().toggle()

Now I can go off and figure out what else I forgot!