开发者

ActiveRecord::SubclassNotFound error when using STI in Rails

I am using Ruby on Rails 2.3.10. I have a class, School. I use STI to give me several subclasses: PrimarySchool, SecondarySchool and University.

app/models/primary_school.rb:
  class PrimarySchool < School
     has_many :education_records, :foreign_key => "school_id"
  end

app/models/secondary_school.rb:
  class SecondarySchool < School
     has_many :education_开发者_StackOverflow社区records, :foreign_key => "school_id"
  end

app/models/university.rb
  class University < School
     has_and_belongs_to_many :applicants, :join_table => :applicants_schools, :foreign_key => "school_id"
  end

db/migrate/20100824170203_create_schools.rb:
class CreateSchools < ActiveRecord::Migration
  def self.up
    create_table :schools do |t|
      t.string :name
      t.string :type     # secondary, cegep, college, university
      t.string :street
      ...
      t.timestamps
    end
  end

  def self.down
    drop_table :schools
  end
end

PrimarySchool.first and PrimarySchool.last work as expected. SecondarySchool.first and SecondarySchool.last work as expected. University.last works.

However, University.first and University.all raise a ActiveRecord::SubclassNotFound exception:

ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'University'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite University.inheritance_column to use another column for that information.
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.10/lib/active_record/base.rb:1671:in `instantiate'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.10/lib/active_record/base.rb:665:in `find_by_sql'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.10/lib/active_record/base.rb:665:in `collect!'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.10/lib/active_record/base.rb:665:in `find_by_sql'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.10/lib/active_record/base.rb:1582:in `find_every'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.10/lib/active_record/base.rb:619:in `find'
    from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.10/lib/active_record/base.rb:639:in `all'
    from (irb):6
    from :0

The SQL generated is correct:

  SecondarySchool Load (0.3ms)   SELECT * FROM `schools` WHERE ( (`schools`.`type` = 'University' ) ) LIMIT 1
  SecondarySchool Load (1.7ms)   SELECT * FROM `schools` WHERE ( (`schools`.`type` = 'University' ) ) ORDER BY schools.id DESC LIMIT 1

What am I missing/doing wrong?


This is a known issue in the development mode.

One workaround is to register the subclasses at the bottom of the base class file.

%w(secondary_school university).each do |r| 
  require_dependency r
end if Rails.env.development?


KandadaBoggu put me on the right track. Pete P.'s workaround works for me:

class School < ActiveRecord::Base
  def self.subclasses
    [PrimarySchool, SecondarySchool, OtherSchool, University]
  end
end

In that it gets rid of the exception...but it generates the wrong SQL:

SELECT * FROM `schools` WHERE ( (`schools`.`type` = 'University' OR
`schools`.`type` = 'PrimarySchool' OR `schools`.`type` = 'SecondarySchool' OR 
`schools`.`type` = 'OtherSchool' OR `schools`.`type` = 'PostSecondaryInstitution' OR 
`schools`.`type` = 'Cegep' OR `schools`.`type` = 'College' OR `schools`.`type` = 
'University' ) ) LIMIT 1

Renaming university.rb to uni.rb, changing the class name and UPDATEing the type column made this work. I'm really confused.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜