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:
parent
014347620d
commit
c04cf690f1
1 changed files with 7 additions and 60 deletions
|
@ -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
|
||||
-----------------------
|
||||
|
||||
|
|
Loading…
Reference in a new issue