Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Rails 2.3.2 dirty tracking has error when Observable is included

#4056

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.)

Reported by apathy in action · February 25th, 2010 @ 06:13 PM

State: stale
Milestone: none
Assigned to: nobody
Importance: Low

Activity

  1. Andrea Campi
    Andrea Campi
    • Tag changed from rails 2.3.2 activerecord dirty observable changed nomethoderror to 2.3.2, activerecord, dirty, nomethoderror, observable

    October 16th, 2010 @ 11:50 PM

  2. Ryan Bigg
    Ryan Bigg
    • State changed from new to stale
    • Importance changed from to Low

    Please comment on this ticket if this is still an issue with 2.3.10.

    October 17th, 2010 @ 07:43 AM