$ the-wire · showcase
Ractor-safe Active Record reflections and a faster BroadcastLogger
By RepoJournal · Filed · About Rails · Composed from the cited sources · methodology
Rails is pushing Active Record toward Ractor compatibility with eager-frozen reflection caches, while a separate patch speeds up the default logger's hot path.
Active Record's reflection cache was the blocker preventing `Post.find`, `Post.where`, and similar calls from running inside a Ractor, because the cache was not frozen. The fix deep-freezes both the reflection and the aggregated reflection, following the pattern of earlier Ractor safety work that eager-loads otherwise lazily memoized values [1]. Expect the same review attention as prior Ractor patches: lazy memoization has to go before the object can be shared across Ractors.
In the same Ractor-safety effort, `timestamp_attributes_for` moves into `SchemaContext` and is computed when the schema loads rather than lazily. As long as the schema is loaded on the main Ractor, those values can then be used on non-main Ractors, and the `reload_from_schema_cache` hook is no longer needed because the `SchemaContext` object is discarded on reload [2]. A related change stops writing to the reloader class when there is nothing to reload, which helps Ractor workers that never need a reload avoid writing to the Reloader instance variable [3].
On the performance side, `BroadcastLogger` is the default logger and usually broadcasts to a single other logger, so `logger.debug` calls that are filtered out by the log level sit on a hot path. Where possible the dispatch now delegates directly via argument forwarding, skipping the arg array, kwarg hash, and method lookup from `send`, which is well optimized in Ruby 4.0 and later [4]. The multiple-logger case still falls back to the general path.
Action Cable users get a documentation fix: the guide's connection callbacks section has been corrected [5]. No behavior change, but worth pulling if you were following the old text.
Action items
- → Review the eager-frozen reflection cache before enabling Ractor workers on Active Record rails/rails [monitor]
- → Pull the BroadcastLogger dispatch change if your app logs heavily at levels above debug rails/rails [plan]
- → Re-read the Action Cable connection callbacks guide for the corrected examples rails/rails [monitor]
References
- [1] Introduce CoW when adding Active Record reflections ↗ rails/rails
- [2] Move timestamp_attributes_for into SchemaContext ↗ rails/rails
- [3] Don't write to the reloader class when there is nothing to reload ↗ rails/rails
- [4] Speed up dispatch of BroadcastLogger ↗ rails/rails
- [5] Fix Action Cable guide for connection callbacks ↗ rails/rails