Reputation: 597
In my database I have a table people
, and I'm using single table inheritance, with these classes:
class Person < ActiveRecord::Base
end
class Member < Person
end
class Business < Member
end
The queries it generates confuse me. What I want is for Member.all
to return all Businesses as well as any other subtypes of Member. Which it does, but only if I've accessed the Business class recently. I assume it's because my classes aren't being cached in development mode (for obvious reasons), but it still seems like strange/buggy behaviour.
Is this a bug in rails? Or is it working as intended? In either case, can anyone think of a good fix for development purposes?
Upvotes: 9
Views: 2112
Reputation: 1943
This is intentional behaviour—the official Rails guide on Autoloading and Reloading Constants explains it pretty well in the section on Autoloading and STI:
…
A way to ensure this works correctly regardless of the order of execution is to load the leaves of the tree by hand at the bottom of the file that defines the root class:
# app/models/polygon.rb class Polygon < ApplicationRecord end require_dependency 'square'
Only the leaves that are at least grandchildren need to be loaded this way. Direct subclasses do not need to be preloaded. If the hierarchy is deeper, intermediate classes will be autoloaded recursively from the bottom because their constant will appear in the class definitions as superclass.
So in your case, this would mean putting an require_dependency "business"
at the end of your Person class.
However, beware of circular dependencies which can possibly be avoided by using require
instead of require_dependency
(even though it may prohibit Rails from tracking and reloading your files when changes are made—after all, require_dependency
is a Rails-internal method).
Upvotes: 5
Reputation: 8777
By default, Rails is not eager loading your classes in development. Try changing the following line in your config/environments/development.rb
:
# Do not eager load code on boot.
config.eager_load = false
to:
# Do eager load code on boot!
config.eager_load = true
Upvotes: 3