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

Ticket #5704 (closed defect: duplicate)

Opened 2 years ago

Last modified 1 year ago

[PATCH] Bug in ActiveRecord::Base when mixing STI and abstract models

Reported by: nick+rails@ag.arizona.edu Assigned to: David
Priority: normal Milestone: 1.2
Component: ActiveRecord Version: edge
Severity: normal Keywords: sti abstract
Cc: bitsweat

Description

Suppose I have a hierarchy of models using single table inheritance in which the base class inherits from an abstract model:

  • BaseModel < ActiveRecord::Base (BaseModel is abstract)
  • Person < BaseModel
  • Employee < Person
  • Contractor < Person

Because of this bug, the following code doesn't work as it should. (Assume the people table has already been populated with Employees and Contractors.)

$ ./script console
Loading development environment.
>> Person.find_first
=> nil

Curiously, Person "learns" about its subclasses as they're used (note that find_first is arbitrary here; any find method elicits the same behavior):

>> Employee.find_first
=> #First employee
>> Person.find_all
=> #All the employees...
>> Contractor.find_first
=> #First contractor
>> Person.find_all
=> #Now, all the employees AND all the contractors

I tracked all of this down to Base#descends_from_active_record?. When building queries, type conditions are only skipped when the superclass is Base; the superclass being an abstract model should, however, also be sufficient to prevent the conditions from being added.

I didn't write any fresh unit tests, but the attached patch seems to address the problem without causing any new ones.

Attachments

abstract_base_sti.diff (2.4 kB) - added by nick+rails@ag.arizona.edu on 08/03/06 22:25:53.

Change History

08/03/06 22:25:53 changed by nick+rails@ag.arizona.edu

  • attachment abstract_base_sti.diff added.

(follow-up: ↓ 2 ) 08/04/06 08:33:06 changed by bitsweat

  • cc set to bitsweat.

Nice catch. Please include an updated test case demoing the bug and its fix.

(in reply to: ↑ 1 ) 11/30/06 21:44:59 changed by zenspider

The gist of the test is below, but it isn't reproducible in that form. I finally figured out that it is only through the const_missing mechanism that this reproduces. Our workaround is to simply refer to all subclasses of all STI trees in config/environment.rb (read: ignored = [Sub1, Sub2, Sub3]). If you can convert this into a test, it would have to have a fairly complete setup (app/models/*) including pre-loaded data to properly reproduce. None of the row's classes can be loaded at the time of testing. At that stage, the test is just 'assert Concrete.find(:all).size > 0'.

Even if the test can't be converted, can this bug PLEASE get patched?

Code below:

#!/usr/local/bin/ruby

require File.dirname(FILE) + '/config/environment'

c = ActiveRecord::Base.connection c.create_table :concretes, :force => true do |t|

t.column "stuff", :text t.column "type", :string, :default => "SubConcrete3"

end

class Abstract < ActiveRecord::Base

self.abstract_class = true

end

class Concrete < Abstract

self.abstract_class = false

end

class SubConcrete1 < Concrete; end class SubConcrete2 < Concrete; end class SubConcrete3 < Concrete; end

instance = SubConcrete1.new instance.stuff = "stuff1" instance.save!

p Concrete.find :all

12/01/06 21:24:48 changed by bitsweat

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

(In [5660]) Subclasses of an abstract class work with single-table inheritance. Closes #5704.

12/01/06 21:30:11 changed by bitsweat

  • keywords set to sti abstract.
  • milestone set to 1.2.

12/19/06 19:47:22 changed by bitsweat

(In [5753]) Partially revert [5660] - makes more trouble than it resolves. References #5704, closes #6766.

01/06/07 01:07:34 changed by bitsweat

  • status changed from closed to reopened.
  • resolution deleted.

01/22/07 01:28:22 changed by BertG

  • version changed from 1.1.0 to edge.

I noticed this a tad bit to late, but I also provided a patch Ticket #7284 to address this problem. (fixed, test + comments)

I think I solved this problem, without introducing new problems, this is proven by the way I test. By changing one of the commonly used Test models (Company) to inherit from an Abstract class I made a good test case.

Without the fix this change would fail 9 tests and create one error. With my fix, all problems are gone.

Maybe we should merge these 2 tickets?

01/23/07 03:17:38 changed by bitsweat

  • status changed from reopened to closed.
  • resolution set to duplicate.

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

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