Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #7284 (new defect)

Opened 1 year ago

Last modified 7 months ago

[PATCH] Abstract class and Inheritance fix

Reported by: BertG Assigned to: bitsweat
Priority: normal Milestone:
Component: ActiveRecord Version: 2.0.1
Severity: normal Keywords: descends_from_active_record inheritance abstract class
Cc: bitsweat

Description

When combining ActiveRecord's ability to use Abstract classes and single table inheritance in some cases (When the base class that inherites ActiveRecord::Base is abstract) find queries might fail.

When the first non-abstract class in the inheritance tree is used to do a query, ActiveRecord will fail to load other classes that are inheriting it. ActiveRecord wrongfully presumes that this class does not Directly descend from ActiveRecord (using the descends_from_active_record? method).

This method should return true if a class is the first non-abstract class to inherit from ActiveRecord.

For this I changed the setup of the current tests, (Company no inherits from AbstractCompany). If my patch would be unnecessary, it should have had no influences on the tests that use the Company object (and the objects that inherit from it). However, after the change I had 9 failures and 1 error. After applying the patch everything went back to 0 failures and 0 errors. I also added 1 more test, to accentuate my point.

One changes that might be discussed is the name of the descends_from_active_record? function to something more suitable.

Attachments

AbstractClassAndInheritancePatch.diff (2.0 kB) - added by BertG on 01/22/07 00:48:59.

Change History

01/22/07 00:48:59 changed by BertG

  • attachment AbstractClassAndInheritancePatch.diff added.

01/22/07 01:30:51 changed by BertG

Also see Patch #5704

01/23/07 04:19:20 changed by bitsweat

  • status changed from new to closed.
  • resolution set to fixed.

(In [6013]) Subclasses of an abstract class work with single-table inheritance. References #5704, closes #7284.

12/10/07 15:47:58 changed by mrj

  • status changed from closed to reopened.
  • severity changed from major to normal.
  • priority changed from high to normal.
  • version changed from edge to 2.0.1.
  • milestone deleted.
  • resolution deleted.

STI is incorrectly disabled in situations like:

class AbstractClass < ActiveRecord::Base
class ConcreteClass1 < AbstractClass
class ConcreteClass2 < AbstractClass

what's wrong with

def self.descends_from_active_record? # Better method name: no_sti?
  self.abstract_class? || !columns_hash.include?(inheritance_column)
end

, setting the type field for AR descendants as well?

12/10/07 19:29:42 changed by BertG

  • owner changed from core to BertG.
  • status changed from reopened to new.

Hey,

This is the same issue i fixed in the past, sadly it was overwritten by a later changeset (including the test). I will create an other changeset (with the test).

I suggest there should be an investigation on how this issue could have been reintroduced.

12/10/07 20:20:25 changed by BertG

  • cc set to bitsweat.
  • owner changed from BertG to bitsweat.
  • version changed from 2.0.1 to 1.2.6.
  • milestone set to 1.2.7.

Ok,

So apparently the fix is reintroduced with Rails 2.0, but in the older 1.2.x series the patch has disappeared.

I suggest that bitsweat applies changeset [6013] to the 1.2.x branch in the next maintenance release.

12/11/07 01:33:10 changed by mrj

  • version changed from 1.2.6 to 2.0.1.
  • milestone deleted.

I'm seeing the problem on 2.0.1, not 1.2.6. It seems STI is only set up to handle class chains, not arbitrary class hierarchies, some classes being abstract. If there's a concrete class on another chain, it won't be detected for the purposes of enabling STI.

In the AR unit tests, you could add a GroupOfCompanies concrete class that descends from AbstractCompany. The aim would be to ensure that the type field gets set on GroupOfCompanies objects, to differentiate them from Company objects.

I'm now running 2.0.1 with the monkey patch

class ActiveRecord::Base
  def self.descends_from_active_record?
    superclass == self || !columns_hash.include?(inheritance_column) || self.abstract_class?
  end
end

but this breaks many AR unit tests. But is it just that the test conditions should be changed?

Bert, I don't yet understand why your original patch was needed. Could you please explain what it fixed, and how you think STI should work. What's wrong with the my code above for deciding whether to put something in the inheritance field? Table names seem to be correctly determined.

12/16/07 17:05:15 changed by mrj

Make that monkey patch

class ActiveRecord::Base
  def self.descends_from_active_record?
    superclass == ActiveRecord::Base || !columns_hash.include?(inheritance_column) || self.abstract_class?
  end
end