Creating Virtual Columns in Rails 7: A Step-by-Step Guide

Rails 7 brings a host of new features and improvements, making it even easier to build robust and maintainable web applications. One of the powerful features available in Rails is the ability to create virtual (or computed/generated) columns in your database tables. In this blog post, we’ll explore how to create a virtual column in Rails 7 along with detailed explanations and examples.

What Are Virtual Columns?

Virtual columns are database columns that are not directly stored but computed based on expressions involving other columns. They can be particularly useful for derived data, such as concatenations, calculations, or transformations that should always be consistent with the source data.

Example Scenario

Let’s say we have a PersonalDocuments table, and we want to add a full_name column that stores a person’s full name and a virtual column full_name_length that calculates the length of the full_name.

Creating the Migration

To create the PersonalDocuments table with the required columns, we will use the create_table migration method. Here’s how you can do it:

Migration

1
2
3
4
5
6
7
8
9
10
class CreatePersonalDocuments < ActiveRecord::Migration[7.0]
  def change
    create_table :personal_documents do |t|
      t.string :full_name
      t.virtual :full_name_length, type: :integer, as: "length(full_name)", stored: true

      t.timestamps
    end
  end
end

In this migration:

The stored: true option ensures that the value of full_name_length is calculated when the row is inserted or updated and stored in the database. This makes querying more efficient as the value doesn’t need to be recalculated each time it is accessed.

Updating the Model

In your PersonalDocument model, no special configuration is needed for the virtual column. It will be available as a read-only attribute.

Model

1
2
3
class PersonalDocument < ApplicationRecord
  # Any other model logic
end

Using the Virtual Column

You can now use the full_name_length virtual column just like any other attribute. Here’s an example of how to create a record and access the virtual column:

Usage

1
2
personal_document = PersonalDocument.create(full_name: "John Doe")
puts personal_document.full_name_length  # Outputs: 8

Important Considerations

  1. Stored vs. Virtual: The stored: true option makes the column a “stored generated” column, meaning its value is calculated when the row is inserted or updated and stored in the database. If you want it to be recalculated on the fly every time it is accessed, you can use stored: false (though support for this varies by database).

Verifying the Setup

After running the migration, you can verify the columns with the following Rails console commands:

1
2
3
4
rails db:migrate
rails console
personal_document = PersonalDocument.create(full_name: "Jane Doe")
puts personal_document.full_name_length  # Should output: 8

This setup ensures that whenever the full_name is updated, the full_name_length virtual column is automatically recalculated and stored.