Hi All,
Recently, in the AR AsscociationProxy class, my colleague and I came across a case that seems to be a violation of the principle of least surprise.
The problem shows itself when trying to take out an elevated lock on an ActiveRecord#Base object: 'ar_obj.reload(:lock => true)'. In general, this works fine. However, if the ar_obj object was not created directly, but instead came from an association proxy off some other AR#base object, then we have a problem. Since AssociationProxy defines its own (no-arg) version of #reload we hit a "wrong number of arguments error" because the object we're calling the method on is of type AssociationProxy, not AR:Base. Thank the stars that the AP#reload method doesn't take an options hash, if that were the case it could be possible to go forward thinking the object was having its lock elevated as expected. With the problem understood it was easy enough to work around by checking if the object had a #target method and using that target object directly if it did.
So, long story short, the implementation of AssociationProxy exposes itself when using the #reload(:lock => true) technique to elevate a lock. My question to the core is whether or not this is an acceptable side effect of the implementation? In particular, I am curious if using this #reload method of lock escalation is a supported mode of operation, or is there some other means to the same end that is better supported by ActiveRecord? For instance, I suppose I could do this (hopefully the formatting on this doesn't get bojacked): <pre> def do_stuff_with_lock(ar_or_ap_object) transaction do ar_or_ap_object.class.find(ar_or_ap_object.id, :lock => true) # do stuff with ar_or_ap_object ar_or_ap_object.save end end </pre>
Cheers, Andrew