after_update attributes problem

Hey guys,

I'm having a hard time w/ the after_update callback on rails... As far as I can tell, when I define a after_update callback on a model, the attributes of the object have the same values that they had *before* Base.save was called. I'm probably wrong so here's the code:

UNIT TEST:   def test_register_item_adjusts_account_balance     account = accounts(:cams_credit_card)     transaction = RegisterItem.new(:date => '2006-10-31',                                    :description => 'Chinese food',                                    :amount => '-13.44')     transaction.account = account     transaction.save     assert_equal -113.44, account.balance #this assertion passes

    transaction.amount = -15.50     transaction.save     assert_equal -115.50, account.balance # FAILS

    transaction.destroy     assert_equal -100.00, account.balance #this assertion will pass   end

FAILURE OUTPUT: Loaded suite test/unit/register_item_test Started .F. Finished in 0.202591 seconds.

  1) Failure: test_register_item_adjusts_account_balance(RegisterItemTest) [test/unit/register_item_test.rb:31]: <-115.5> expected but was <-113.44>.

3 tests, 6 assertions, 1 failures, 0 errors

So changing the amount on a transaction (RegisterItem) should change the current balance of an account. Here's the relevent callbacks:

REGISTER_ITEM UPDATE CALLBACKS:   def before_update     account.balance -= amount     account.save   end

  def after_update     account.balance += amount     account.save   end

So the idea is that before the transaction is updated i subtract the amount of the transaction back from the account, and then add the new amount back on. It looks like @amount is still the old value during the after_update callback though. is that correct? how can i access the new value?

Thanks, Cameron Matheson

the steps are:

before_update [update operation] after_update

so to keep things simple, say your account balance is 0.0:

... # existing transaction transaction.amount = 10.0 # transaction.account.balance = 0.0 still

transaction.save   # before_update: transaction.amount = 10.0, transaction.account.balance = -10.0   # update operation   # after_update: transaction.amount = 10.0, transaction.account.balance = 0.0

so you're back where you started, which is what your test is telling you.

Hey thanks for the response:

so to keep things simple, say your account balance is 0.0:

... # existing transaction transaction.amount = 10.0 # transaction.account.balance = 0.0 still

transaction.save   # before_update: transaction.amount = 10.0, transaction.account.balance = -10.0   # update operation   # after_update: transaction.amount = 10.0, transaction.account.balance = 0.0

so you're back where you started, which is what your test is telling you.

Ok so there is a problem in the way i understand the before_update callback, or in your logic (probably my problem which would explain the bug). Anyway, this is a before/after_*update* callback, it looks like the scenario you're describing is a before/after_*create* kind of deal. so the way i would understand it would be like so:

#account.balance == 0 transaction.amount = 10.0 #transaction.amount formerly == 0 before_update: transaction.amount -= 0\ after_update: transaction.amount += 10 # account.balance == 10

is that wrong? Cameron Matheson

Hey Steve,

Would calling account.reload after the save cause problems for you elsewhere?

I wasn't aware of the reload method. I called it after save and although it didn't cause any problems, it didn't change the behavior of the program either (unless i called self.reload on the transaction, in which case it looks like the after_update callback didn't get called)

Thanks! Cam

these are the callbacks that are run during an update operation

before_validation before_validation_on_update after_validation after_validation_on_update before_save before_update <UPDATE OPERATION> after_update after_save

if you are creating a new record, replace *_update with *_create in the above list. thats the difference.

so, knowing this, we see that your before and after updates will run around the update operation.

# transaction.account.balance = -100.00 transaction.amount = -15.50    transaction.save # before_update, update, after_update

   # before_update callback    # -----------------------------------    # account.balance -= amount    # -100.00 - (-15.50) = -(100.00 - 15.50) = -84.50    # account.save

hey,

follow?

it makes sense... i hadn't understood how it worked previously. i figured that since it was before save was called, that the data would have been the old data. so is there no way to access the previous data w/ callbacks? i guess i could store the old amount in all of the RegisterItem model, but i'd rather not go that route.

thanks, cam