Ruby 1.8.6,
Rails 2.3.2
Windows xp.
The Observable module and the ActiveRecord::Dirty module appear
to be incompatible when the Observable module is included in an
ActiveRecord subclass. This results in a NoMethodError being thrown
in ActiveRecord::Base#attributes_with_quotes(..) which assumes an
Enumerable in its third parameter.
Steps to recreate (using Oracle in this instance):
create table Foo
( id number(9), created_at date, updated_at date );
class Foo < ActiveRecord::Base
end
f=Foo.new()
f.id=(1)
f.save()
f=Foo.first()
f.changed()
=> [] f.changed?
=> false f.id=(2)
=> 2 f.changed()
=> ["id"] f.changed?
=> true
This is the expected behaviour with dirty tracking.
Foo.send( :include, Observable )
f=Foo.first()
=> Foo(created_at: datetime, updated_at: datetime, id: integer)
b.changed()
=> true b.changed?
=> true
The Observable module's implementations of #changed and
#changed? replace those of ActiveRecord::Dirty module.
This can cause an error down in the
ActiveRecord::Base#attributes_with_quotes method which expects an
Enumerable as its #attribute_names parameter, resulting in a
NoMethodError on TrueClass being sent #each.
This comes about due to the above inclusion of Observable which
causes the ActiveRecord::Dirty module's #changed implementation to
be overridden and return a boolean which changes the following when
#partial_updates are enabled (the default):
def update_with_dirty
if partial_updates?
# Serialized attributes should always be written in case they've been
# changed in place.
update_without_dirty(changed | self.class.serialized_attributes.keys)
else
update_without_dirty
end
end
The workaround in our case was to set #partial_updates to false
for any class which included Observable.
One fix is to alter the true block to :
update_without_dirty( changed_attributes().keys() |
self.class.serialized_attributes.keys )
This prevents the NoMethodError from occurring.
The behavior described here does not appear to be present in
2.3.4.
Hope this helps.
sinclair
(ps. tried to use formatting around the code but things went
pear-shaped, sorry.)