This project is archived and is in readonly mode.

#4056 ✓stale
apathy in action

Rails 2.3.2 dirty tracking has error when Observable is included

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

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

Comments and changes to this ticket

  • Andrea Campi

    Andrea Campi October 16th, 2010 @ 11:50 PM

    • Tag changed from rails 2.3.2 activerecord dirty observable changed nomethoderror to 2.3.2, activerecord, dirty, nomethoderror, observable
  • Ryan Bigg

    Ryan Bigg October 17th, 2010 @ 07:43 AM

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

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages