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 &lt; 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&lt;q\xB1.&lt;~\xA3m\e\x8C\t\xCF&amp;/3\xCE\xAE"'
    key = ActiveSupport::KeyGenerator.new('password').generate_key(salt)

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


user.rb

class User &lt; ApplicationRecord
  encrypt_columns :email, :social_security_number
end
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. It can be a file not committed to the repository.



I'd write the crypt method this way:
  def crypt
    @crypt ||= begin
      key = ActiveSupport::KeyGenerator.new('password').generate_key('salt')    
      ActiveSupport::MessageEncryptor.new(key)
    end
  end