Skip to content

Thin the injection layer: one universal discrimination seam - #14

Merged
voltechs merged 2 commits into
developfrom
refactor/thin-injection
Jun 26, 2026
Merged

voltechs merged 2 commits into
developfrom
refactor/thin-injection

Conversation

@voltechs

Copy link
Copy Markdown
Member

Replaces the version-gated discrimination dispatch with a single feature-detected instantiate_instance_of seam, and simplifies discriminate_class_for_record to read the oid via [] universally.

  • instantiate_instance_of seam — removes the _load_from_sql(7.0+) / reimplemented-find_by_sql(6.x) ActiveRecord.version split + force_mti_instantiation. AR 6.0+ funnel the homogeneous fast path through one signature-stable method; intercept it and re-route through instantiate when the row's tableoid maps to a different class. klass == self bounds the recursion; 5.x (no fast path) is feature-detected out.
  • discriminate_class_for_record — Hash (<=7.1) and IndexedRow (7.2+) both support []; the mti_class != self guard already terminates recursion, so the respond_to?(:delete) branch is gone.

Net -47 lines in core_extension.rb; version-detection -> feature-detection for the dispatch.

Verified locally: Rails 7.0/7.1/7.2/8.0/8.1 green + order-independent (26 seeds); composes clean with active_record-progresql. This PR runs the full 5.2->8.1 matrix.

(Note: dropping add_tableoid_column was attempted and reverted — its load_schema! hook is the eager-registration trigger, not cosmetic.)

voltechs added 2 commits June 25, 2026 19:02
…stance_of seam

Rails 6.0+ added a homogeneous fast path (instantiate_instance_of) that skips
discriminate_class_for_record when the result lacks the STI inheritance_column;
MTI discriminates on tableoid, so it was forced back onto the discriminating path
by overriding _load_from_sql (7.0+) and *reimplementing* find_by_sql (6.x) behind
an ActiveRecord.version gate.

Both eras funnel through the same signature-stable instantiate_instance_of(klass,
attributes, column_types, &block). Intercept that one method instead: re-route to
`instantiate` when the row's tableoid maps to a different class. The `klass == self`
guard matches only AR's homogeneous call, so post-discrimination re-entry terminates
(and STI-within-MTI resolves via super). 5.x has no fast path -> feature detection
skips the hook.

Removes the version if/elsif, the find_by_sql reimplementation, and
force_mti_instantiation: ~55 lines -> ~10, version-detection -> feature-detection.
Verified green on AR 7.0 and 8.1 (order-independent).
Both the mutable Hash (Rails <= 7.1) and the read-only IndexedRow (7.2+) support #[],
and the mti_class != self guard already terminates the recursion, so the
respond_to?(:delete) branch (and the mutation it implied) is gone. Verified on AR
7.0 (Hash) and 8.1 (IndexedRow).
@voltechs
voltechs merged commit 84650cf into develop Jun 26, 2026
9 checks passed
@voltechs
voltechs deleted the refactor/thin-injection branch June 26, 2026 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant