ActiveRecord::Observer i dirty object

Chcę przenieść masę wywołań after_save :cos_tam do observera. Poniżej jak to wygląda.

[code]class OperationObserver < ActiveRecord::Observer
observe :operation

def after_update(operation)
if operation.account_id_changed?
old_account = Account.find(operation.account_id_was)
update_account_balance(old_account, operation.amount * -1)
update_account_balance(operation.account, operation.amount)
end

if operation.amount_changed?
  amount_diff = operation.amount - (operation.amount_was / 100.0)
  update_account_balance(operation.account, amount_diff)
end

end

protected

def update_account_balance(account, amount)
account.update_attributes!(:balance => account.balance + amount)
end
end[/code]
Kiedy robię:

@operation.account = some_other_account @operation.save
wszystko ładnie działa

Kiedy robię

@operation.update_attributes!(:account_id => some_othe_account.id)

to bilans obu kont pozostaje niezmienny.

Coś mnie omija i nie wiem czemu przy update_attributes nie dziala

Masz jakieś zabezpieczenia przed mass assignments?
Może trzeba dodać

attr_accessible :account_id

RawOnRails nie ma tam ani attr_accessible, ani attr_protected

Sprawdź czy observer jest na pewno uruchamiany i czy account_id_was nie jest takie samo jak account_id.

Co do samej architektury: nazwy Operation i Account sugerują, że masz do czynienia z jakimiś danymi finansowymi. W takim wypadku zmiana Operation nie powinna być możliwa a już na pewno nie powinno dać się zmienić Account powiązanego z Operation. Coś tu mocno śmierdzi :slight_smile:

Observer jest na pewno uruchamiany i masz rację account_id_was jest taki sam jak account_id. Czy wiesz może czemu tak się dzieje w przypadku uzycia update_attributes?

Nie zaciągaj się za mocno Bragi bo w tym kodzie dużo śmierdzi, ale staram się to pozmieniac troche :wink:

A ogólnie podejście w ten sposób robienie tego przez obserwatorów wydaje się Wam dobre czy lepiej rozrzucić to po modułach?

Z tego, co pamiętam, to problem tkwi w after_update. Po wykonaniu update_attributes obiekt jest przeładowywany i traci wszelkie informacje o zmianach (co można sprawdzić wywołując metodę Account#changes, która zwróci pusty hash). Jeśli przeniósłbyś zmiana balance do before_update, wtedy wszystko powinno działac jak trzeba.