1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Document easier way to preload STIs

This commit is contained in:
Xavier Noria 2021-09-26 10:20:56 +02:00
parent 014347620d
commit c04cf690f1

View file

@ -314,72 +314,19 @@ Single Table Inheritance is a feature that doesn't play well with lazy loading.
In a sense, applications need to eager load STI hierarchies regardless of the loading mode.
Of course, if the application eager loads on boot, that is already accomplished. When it does not, it is in practice enough to instantiate the existing types in the database, which in development or test modes is usually fine. One way to do that is to include an STI preloading module in your `lib` directory:
Of course, if the application eager loads on boot, that is already accomplished. When it does not, it is in practice enough to instantiate the existing types in the database, which in development or test modes is usually fine:
```ruby
module StiPreload
unless Rails.application.config.eager_load
extend ActiveSupport::Concern
included do
cattr_accessor :preloaded, instance_accessor: false
end
class_methods do
def descendants
preload_sti unless preloaded
super
end
# Constantizes all types present in the database. There might be more on
# disk, but that does not matter in practice as far as the STI API is
# concerned.
#
# Assumes store_full_sti_class is true, the default.
def preload_sti
types_in_db = \
base_class.
unscoped.
select(inheritance_column).
distinct.
pluck(inheritance_column).
compact
types_in_db.each do |type|
logger.debug("Preloading STI type #{type}")
type.constantize
end
self.preloaded = true
end
end
# config/initializers/preload_stis.rb
unless Rails.application.config.eager_load
Rails.autoloaders.main.on_load("RootSTIModel") do |klass|
klass.connection.select_values(<<~SQL).each(&:constantize)
SELECT DISTINCT("#{klass.inheritance_column}") FROM "#{klass.table_name}"
SQL
end
end
```
and then include it in the STI root classes of your project:
```ruby
# app/models/shape.rb
require "sti_preload"
class Shape < ApplicationRecord
include StiPreload # Only in the root class.
end
```
```ruby
# app/models/polygon.rb
class Polygon < Shape
end
```
```ruby
# app/models/triangle.rb
class Triangle < Polygon
end
```
Customizing Inflections
-----------------------