# Simple ActiveRecord attributes encryption in Rails 5+

The task at hand was to ensure that certain columns in the database are encrypted in case the database data is stolen. I have a feeling that a lot can be improved here (naming, DSL, encapsulations) while keeping the functionality as simple as it is. Let me know what you think, I'd appreciate any suggestions and ideas!

application_record.rb

class ApplicationRecord < ActiveRecord::Base
extend Encryptable
#...
end


encryptable.rb

module Encryptable
def encrypt_columns(*columns)
columns.each do |column|
if self.column_names.include?(column.to_s)
define_method "#{column}=" do |value|
self[column] = self.class.crypt.encrypt_and_sign(value)
end

define_method "#{column}" do
self.class.crypt.decrypt_and_verify(self[column])
end
end
end
end

def crypt
salt = '"\xCA)P\x9Dbc\xF7\x85B\xF3v}*p\xA6~\xBAR\xC1K\xE3\x88\xB8\x18\xF7\xD1\xB6e0\x98\xEF \xB9%\xB3\x12\x9C\xFE,\x89\xF4\xDE\xED!:7\xAE<q\xB1.<~\xA3m\e\x8C\t\xCF&/3\xCE\xAE"'

@crypt ||= ActiveSupport::MessageEncryptor.new(key)
end
end


user.rb

class User < ApplicationRecord
encrypt_columns :email, :social_security_number
end

• Step 1: Don't hard-code your salt and password... – Flambino Aug 31 '16 at 15:44

Some notes:

• The recommended way to overwrite accessors is to use super.

• As @Flambino says, it's better not to hardcode secrets directly in the code. The can be in a configuration file not commited to the repository.

• I'd write the crypt method this way:

def crypt
@crypt ||= begin