← All articles
development

How to Migrate to Rails Encrypted Attributes

How to migrate an existing unencrypted Rails column to Rails 7's built-in encrypted attributes without breaking data already in the database.

Donn Felker

Donn Felker

2023.04.26 · 1 min read

This post will show you how to migrate an existing attribute to a Rails 7 encrypted attribute.

Rails 7 has shipped with encrypted attributes, so its no longer necessary to use something like attr_encrypted to encrypt a field.

Once set up, using it is easy:

class Person < ApplicationRecord
encrypts :ssn
end

This works great if you have never happened to have any unencrypted values in your model. But what if you have an existing attribute that’s not encrypted and want to make it encrypted? Here’s how to do it …

How to migrate an existing attribute to an encrypted attribute

Let’s assume you forgot to encrypt your :ssn attribute on the Person class:

class Person < ApplicationRecord
# has a first_name, last_name, ssn, etc
# none are encrypted
end

Let’s assume you forgot to encrypt your :ssn attribute on the Person class:

  1. Run the installer: rails db:encryption:init
    • This will add active_record_encryption values to your target environment credentials. Be sure to add it to your other environments too. (more info)
  2. Set config.active_record.encryption.support_unencrypted_data = true in your environment files. e.g. – production.rb and developement.rb
  3. Encrypt the field:
class Person < ApplicationRecord
encrypts :ssn
end

4. Generate a migration to encrypt the existing values:

class EncryptPersonDetails < ActiveRecord::Migration[7.0]
def up
people = Person.all
people.each do |person|
person.encrypt
end
end
def down
# Needed in the config you're using (production.rb, development.rb)
# config.active_record.encryption.support_unencrypted_data = true
people = Person.all
people.each do |person|
person.decrypt
end
end
end

5. Commit and deploy

6. Once migrated, create another commit that removes the following: config.active_record.encryption.support_unencrypted_data = true from your environment files and deploy that.

That’s it; now your Person model has an encrypted field. Enjoy.

More info: Active Record Encryption docs

Donn Felker

Written by Donn Felker

I've spent 25+ years shipping software, writing books, and running my own companies. I write about thinking clearly, working for yourself, and doing real work while AI rewrites the rules. New essays land here every week.

Get the newsletter

Keep reading