Virtual columns, real bugfixes
👋 Welcome to the very first issue of Rails Decoded! This is Omar Rashad, You're one of the founding subscribers helping shape a newsletter that breaks down Rails changes. Each week, I'll take "This Week in Rails" and translate it into small chunks-friendly explanations with real use cases.
Table of Contents
Top Picks
PostgreSQL, Rails and virtual columns — Models & Data (Active Record)
You know how sometimes you need a calculated column—like a lowercase version of a name or a string's length—but you don't want to waste database space storing it? That's exactly what virtual columns solve.
PostgreSQL has supported virtual (non-persisted) generated columns since version 12. What's new is that Rails migrations now have clean API support for specifying stored: false
. Previously, you'd need to use raw SQL via execute
to create virtual columns. Unlike stored generated columns (which save the calculated value to disk), virtual columns compute the value on-the-fly every time you query them.
Real scenario: You're building a search feature that needs case-insensitive matching on usernames. Instead of creating a separate lower_username
column that duplicates data, you create a virtual column that computes LOWER(username)
dynamically. Your database stays lean, and the calculation happens at query time using PostgreSQL's native functions.
Example
create_table :users do |t|
t.string :name
t.virtual :lower_name, type: :string, as: "LOWER(name)", stored: false
t.virtual :name_length, type: :integer, as: "LENGTH(name)"
end
# Query using the virtual column
User.where("lower_name = ?", "john")
When to care: Building case-insensitive searches, computing derived values (full names from first+last), or reducing data duplication
Config: Requires PostgreSQL 12+ and Rails with this patch. Use stored: false
to make it virtual (not persisted)
Source: PR #55142
Parallel test worker crash handling — Testing & Developer Tools
Imagine you're running your test suite with parallel workers (to make tests faster), and one worker crashes unexpectedly—maybe it hits an out-of-memory error or segfaults. Before this fix, the entire test suite would hang forever waiting for that dead worker to finish.
Rails now tracks both worker IDs and their process IDs (PIDs). When a worker dies abruptly, Rails can map the dead process back to its worker entry and clean it up properly, allowing the test suite to continue or fail gracefully instead of hanging.
Real scenario: You're running rails test --parallel
with 8 workers. Worker #5 crashes due to a memory leak in a specific test. Previously, the other 7 workers would finish but the suite would hang forever waiting for worker #5. Now, Rails detects the crash, cleans up worker #5's resources, and reports the failure so you can investigate.
Example
# Run tests in parallel
$ rails test --parallel
# Before: Would hang if a worker crashed
# After: Detects crash, cleans up, reports failure
# [Worker 5] Process crashed (PID 12345)
# [Test suite] Cleaning up failed worker...
When to care: Running parallel tests in CI/CD pipelines, debugging flaky tests that cause crashes, or working with large test suites
Config: Works automatically with rails test --parallel
- no configuration needed
Source: PR #55794
Short Explainers
Parallel test replica setup: Integration tests running in parallel now correctly use numbered parallel worker databases (like
test_2
,test_3
) instead of accidentally selecting the basetest
database. This prevents test isolation issues where parallel workers interfere with each other's data. Important if you're using database replicas in your test setup.Autosave regression fix: Rails 8.0.2 introduced a bug where valid models could become invalid through autosave when a distantly related record (think:
user.posts.comments
) was deleted via nested attributes (accepts_nested_attributes_for). This fix restores the correct behavior so deletions don't cascade validation failures unexpectedly.Composite foreign key unset fix: If you're using composite foreign keys (multiple columns as a foreign key), trying to unset the association (set it to nil) would raise an error. This fix allows you to properly clear composite foreign key associations without crashes.
Verbose redirect logs: Remember last week's redirect source logging feature? Rails now includes the config setting
action_dispatch.verbose_redirect_logs
to enable it. When true, every redirect in your logs shows exactly which file and line number triggered it—super helpful for debugging authentication flows.
Why this week changes matters
If you're on PostgreSQL and want smarter database design, virtual columns are a game-changer for reducing data duplication. And if parallel tests have ever hung on you in CI, that fix alone will save hours of debugging time.
The autosave and composite key fixes are critical if you hit those bugs—Rails 8.0.2 broke some previously valid code, so update soon if you're affected.
Next steps: If you're on PostgreSQL 18, try adding a virtual column for a common search or calculation in your app. Run EXPLAIN ANALYZE
to see how it performs compared to a stored column!
Full changelog: Compare changes • 15 contributors this week
Resources:
— Omar Rashad