Skip to content

appfolio/store_base_sti_class

Repository files navigation

StoreBaseSTIClass

ActiveRecord has always stored the base class in polymorphic_type columns when using STI. This can have non-trivial performance implications in certain cases. This gem adds the store_base_sti_class configuration option which controls whether ActiveRecord will store the base class or the actual class. Defaults to true for backwards compatibility.

Description

Given the following class definitions:

class Address
  belongs_to :addressable, polymorphic: true
end

class Person
  has_many :addresses, as: addressable
end

class Vendor < Person
end

and given the following code:

vendor = Vendor.create(...)
address = vendor.addresses.create(...)

p vendor
p address

will output:

#<Vendor id: 1, type: "Vendor" ...>
#<Address id: 1, addressable_id: 1, addressable_type: 'Person' ...>

Notice that addressable_type column is Person even though the actual class is Vendor.

Normally, this isn't a problem, however, it can have negative performance characteristics in certain circumstances. The most obvious one is that a join with persons or an extra query is required to find out the actual type of addressable.

This gem adds the ActiveRecord::Base.store_base_sti_class configuration option. It defaults to true for backwards compatibility. Setting it to false will alter ActiveRecord's behavior to store the actual class in polymorphic_type columns when STI is used.

In the example above, if the ActiveRecord::Base.store_base_sti_class is false, the output will be,

#<Vendor id: 1, type: "Vendor" ...>
#<Address id: 1, addressable_id: 1, addressable_type: 'Vendor' ...>

Usage

Add the following line to your Gemfile

gem 'store_base_sti_class'

then bundle install. Once you have the gem installed, add the following to one of the initializers (or make a new one) in config/initializers,

ActiveRecord::Base.store_base_sti_class = false

When changing this behavior, you will have write a migration to update all of your existing _type columns accordingly. You may also need to change your application if it explicitly relies on the _type columns.

Notes

This gem incorporates work from:

It currently works with ActiveRecord 4.2.x through 7.0.x. If you need support for ActiveRecord 3.x, use a pre-1.0 version of the gem, or ActiveRecord < 4.2 use a pre-2.0 version of the gem, or ActiveRecord < 6 use version < 3 of the gem.

Conflicts

This gem produces known conflicts with these other gems:

When using friendly_id >= 5.2.5 with the History module enabled, duplicate slugs will be generated for STI subclasses with the same sluggable identifier (ex: name). This will either cause saves to fail if you have the proper indexes in place, or will cause slug lookups to be non-deterministic, either of which is undesirable.

History

About

Modifies ActiveRecord 4+ with the ability to store the actual class (instead of the base class) in polymorphic _type columns when using STI

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages