Updating attribute on dependent of many-to-on association

All,

I posted this over on comp.lang.ruby, but realized I should probably keep Rails questions to this group, so soory for the cross-post.

I have a rails app with a Transaction class that has_many :entries. Each Transaction has many entries, and those with the debit attribute true are debits, false are credits. It starts like this.

class Transaction < ActiveRecord::Base   has_many :entries   has_many :debits, :class_name => 'Entry', :conditions => {:debit => true}   has_many :credits, :class_name => 'Entry', :conditions => {:debit => false} end

I want to be able to complete an Transaction if there is exactly one Entry that has its amount set to nil. I want to set that amount to a debit or credit of the proper amount to make the Transaction balance.

Sounded easy to me, but I am having trouble with my balance! method. The relevant part of it is:

  def balance!     ...     if num_nils == 1       # Set the sole nil entry to amount needed to balance Transaction       plug = debit_total - credit_total       entries.where(:amount => nil).each do |e|         e.amount = plug.abs         e.debit = (plug < 0)         e.save       end     end

The problem is that when I finish this, the entries associated with my Transaction are not affected. I appears to make a copy, change it, and leave the Entry associated with my Transaction with a nil amount.

What am I missing?

Thanks,

Dan Doherty

All,

I posted this over on comp.lang.ruby, but realized I should probably keep Rails questions to this group, so soory for the cross-post.

I have a rails app with a Transaction class that has_many :entries. Each Transaction has many entries, and those with the debit attribute true are debits, false are credits. It starts like this.

class Transaction < ActiveRecord::Base has_many :entries has_many :debits, :class_name => 'Entry', :conditions => {:debit => true} has_many :credits, :class_name => 'Entry', :conditions => {:debit => false} end

I want to be able to complete an Transaction if there is exactly one Entry that has its amount set to nil. I want to set that amount to a debit or credit of the proper amount to make the Transaction balance.

Sounded easy to me, but I am having trouble with my balance! method. The relevant part of it is:

def balance! ... if num_nils == 1 # Set the sole nil entry to amount needed to balance Transaction plug = debit_total - credit_total entries.where(:amount => nil).each do |e| e.amount = plug.abs e.debit = (plug < 0) e.save end end

The problem is that when I finish this, the entries associated with my Transaction are not affected. I appears to make a copy, change it, and leave the Entry associated with my Transaction with a nil amount.

What am I missing?

The first thing to determine is which bit is failing. Is the code in the each loop actually running? Does the save work (check the return code from save)? Have a look at the Rails Guide on debugging for help on how to debug the code.

Not directly related to the question but I find it hard to believe that the way you are going about this is ideal. I suggest it would be better not do directly differentiate between debits and credits as you are, but just to have positive or negative transaction values. However as I know little about what you are trying to achieve this may be incorrect.

Also I suspect that transaction may be a reserved word in rails, so this might give you problems.

Colin

Colin,

Thanks for taking a look at this. After a good night’s sleep, I came back to this, and the problem appears to be that I need to self.reload after the loop. I believe this is because of the nature of the association, which depend on whether debit is true or false, and I believe need re-reading from the db after the e.save.

For anyone interested, here is what fixed it:

if num_nils == 1

  # Set the sole nil entry to amount needed to balance Transaction

  plug = debit_total - credit_total

  entries.where(:amount => nil).each do |e|

    e.amount = plug.abs

    e.debit = (plug < 0)

    e.save

  end
  reload    # <= New line
end

Th