When working with legacy databases or large Rails applications, a model may have more database columns than the application actually needs.
Some columns might belong to an older feature, a third-party integration, or a database structure shared by multiple applications.
Traditionally, Rails developers could use ignored_columns to tell Active Record which columns to ignore. With Rails 8.1, only_columns provides the opposite approach: explicitly list the columns a model should use.
Let’s understand how it works, how to test it in the Rails console, and when it can be useful.
1. What Is only_columns in Rails 8.1?
ActiveRecord::Base.only_columns allows you to specify the database columns that a model should recognize and use.
Instead of listing the columns you want to ignore, you list the columns you want Active Record to use.
Consider a users table with these columns:
id
name
email
phone
address
legacy_reference
external_customer_id
created_at
updated_at
Suppose your application only needs:
- id
- name
- created_at
- updated_at
You can explicitly define that list in your model.
2. How to Use only_columns
Let’s use a User model as an example.
app/models/user.rb
class User < ApplicationRecord
self.only_columns = %w[
id
name
email
created_at
updated_at
]
end
Now, Active Record uses the configured column list when defining model attributes and constructing SQL queries.
The database schema itself remains unchanged. The phone, address, legacy_reference, and external_customer_id columns still exist in the database.
The difference is that this model is configured to work with an explicitly defined subset of those columns.
3. Test It in the Rails Console
One of the easiest ways to understand this feature is to inspect the model directly.
Start the Rails console:
bin/rails console
Check the configured columns:
User.only_columns
Expected output:
["id", "name", "email", "created_at", "updated_at"]
You can also inspect the model’s recognized column names:
User.column_names
The result reflects the columns Active Record recognizes for this model, subject to the configured column list.
To inspect the attributes of a new record:
user = User.new
user.attributes.keys
The attribute list should reflect the configured columns rather than every column in the database table.
This is useful when debugging a model in the Rails console: you can check which columns the model is configured to use without changing the underlying database schema.
4. Why Is This Useful?
A. Working with legacy databases
Imagine you’re maintaining an application that has been running for several years.
Its database contains columns left behind by older features:
users
-----
id
name
email
old_subscription_id
legacy_status
deprecated_reference
created_at
updated_at
Your current application only needs the user’s basic information.
With only_columns, you can explicitly declare the columns that the model should use.
This makes the intended model schema easier to understand and can reduce accidental dependencies on legacy columns.
B. Working with shared database schemas
Some applications share a database with another service or application.
For example, your Rails application might use a customers table that also contains columns maintained by an external integration.
You may not want your application model to depend on every column in that shared table.
An explicit column list helps document the subset that your application expects to use.
Remember, this does not prevent other applications or direct SQL queries from accessing the remaining database columns.
C. Making schema changes safer
Database changes often require careful coordination between deployments.
Suppose you’re planning to remove an obsolete column.
Rather than immediately removing the column from the database, you can first update the application so its model no longer depends on it.
A possible rollout is:
- Identify the columns the application actually needs.
- Configure only_columns to list those columns.
- Deploy the application and verify that it no longer depends on the obsolete column.
- Check other applications, background jobs, reports, and database queries for dependencies.
- Remove the obsolete column in a subsequent deployment when it is safe to do so.
This approach can make a schema migration easier to coordinate, especially when multiple application versions or services share a database.
However, only_columns does not automatically make a migration safe. You still need to verify that no other code depends on the column.
5. How Is only_columns Different from ignored_columns?
Rails already provides ignored_columns, so why introduce another option?
The difference is how you express your intention.
Using ignored_columns
class User < ApplicationRecord
self.ignored_columns = %w[
legacy_reference
deprecated_reference
]
end
This tells Active Record to ignore the listed columns.
It’s convenient when most columns remain relevant and only a few need to be excluded.
Using only_columns
class User < ApplicationRecord
self.only_columns = %w[
id
name
email
created_at
updated_at
]
end
This explicitly lists the columns the model should use.
It’s convenient when you want to define a known subset rather than maintain a list of columns to exclude.
Feature
ignored_columns
only_columns
Approach
List columns to ignore
List columns to use
Best suited for
Excluding a small number of columns
Explicitly defining the model’s column set
Database schema
Unchanged
Unchanged
Can be combined with the other option?
No; use one approach per model
No; use one approach per model
Choose the approach that best communicates your application’s intent.
6. Is only_columns a Security Feature?
No. This distinction is important.
Although only_columns restricts the columns Active Record uses for a model, it should not be treated as a security or authorization mechanism.
For example, suppose your users table contains:
id
name
email
admin
password_digest
Configuring a model to use only id, name, and email does not replace proper authorization, access control, or protection of sensitive information.
You should still implement appropriate authorization policies, validate permitted input, and protect sensitive attributes.
Use only_columns to control the model's expected database columns, not to enforce who can access data.
7. Things to Keep in Mind
Before adopting only_columns, consider the following:
- Associations: Verify that the columns needed for association loading and joins are included.
- Primary keys: Include the primary key or all required composite primary key columns.
- Timestamps: Include created_at and updated_at if the model relies on them.
- Background jobs and callbacks: Check whether callbacks or other application code depend on excluded attributes.
- Schema changes: Confirm that other applications and queries no longer depend on a column before removing it from the database.
- Rails version: Use a patched Rails release. Rails 8.1.4 includes a fix ensuring that only_columns is respected when constructing the SELECT clause. Earlier Rails 8.1 versions may not handle this correctly in all queries.
Also, test the behavior with your actual model and associations before applying it to production.
Conclusion
Rails 8.1’s only_columns provides an explicit way to tell Active Record which database columns a model should use.
It can be useful when working with legacy tables, shared schemas, and staged database changes.
The main takeaway is simple:
ignored_columns tells Rails what to leave out. only_columns tells Rails what to work with.
If you maintain Rails applications with evolving database schemas, this is a feature worth understanding and testing.
For more details, see the Rails 8.1 Release Notes and the Active Record ModelSchema API.
Top comments (0)