123456789_123456789_123456789_123456789_123456789_

Module: ActiveRecord::Encryption::EncryptableRecord

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Included In:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Defined in: activerecord/lib/active_record/encryption/encryptable_record.rb

Overview

This is the concern mixed in Active Record models to make them encryptable. It adds the encrypts attribute declaration, as well as the API to encrypt and decrypt records.

Constant Summary

Class Method Summary

::ActiveSupport::Concern - Extended

class_methods

Define class methods from given block.

included

Evaluate given block in context of base class, so that you can write class macros here.

prepended

Evaluate given block in context of base class, so that you can write class macros here.

append_features, prepend_features

Instance Attribute Summary

Instance Method Summary

DSL Calls

included

[ GitHub ]


10
11
12
13
14
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 10

included do
  class_attribute :encrypted_attributes

  validate :cant_modify_encrypted_attributes_when_frozen, if: -> { has_encrypted_attributes? && ActiveRecord::Encryption.context.frozen_encryption? }
end

Instance Attribute Details

#has_encrypted_attributes?Boolean (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 204

def has_encrypted_attributes?
  self.class.encrypted_attributes.present?
end

Instance Method Details

#_create_record(attribute_names = self.attribute_names) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 178

def _create_record(attribute_names = self.attribute_names)
  if has_encrypted_attributes?
    # Always persist encrypted attributes, because an attribute might be
    # encrypting a column default value.
    attribute_names |= self.class.encrypted_attributes.map(&:to_s)
  end
  super
end

#build_decrypt_attribute_assignments (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 214

def build_decrypt_attribute_assignments
  Array(self.class.encrypted_attributes).to_h do |attribute_name|
    type = type_for_attribute(attribute_name)
    encrypted_value = ciphertext_for(attribute_name)
    new_value = type.deserialize(encrypted_value)
    [attribute_name, new_value]
  end
end

#build_encrypt_attribute_assignments (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 208

def build_encrypt_attribute_assignments
  Array(self.class.encrypted_attributes).index_with do |attribute_name|
    self[attribute_name]
  end
end

#cant_modify_encrypted_attributes_when_frozen (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 223

def cant_modify_encrypted_attributes_when_frozen
  self.class.encrypted_attributes.each do |attribute|
    errors.add(attribute.to_sym, "can't be modified because it is encrypted") if changed_attributes.include?(attribute)
  end
end

#ciphertext_for(attribute_name)

Returns the ciphertext for attribute_name.

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 157

def ciphertext_for(attribute_name)
  if encrypted_attribute?(attribute_name)
    read_attribute_before_type_cast(attribute_name)
  else
    read_attribute_for_database(attribute_name)
  end
end

#decrypt

Decrypts all the encryptable attributes and saves the changes.

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 171

def decrypt
  decrypt_attributes if has_encrypted_attributes?
end

#decrypt_attributes (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 193

def decrypt_attributes
  validate_encryption_allowed

  decrypt_attribute_assignments = build_decrypt_attribute_assignments
  ActiveRecord::Encryption.without_encryption { update_columns decrypt_attribute_assignments }
end

#encrypt

Encrypts all the encryptable attributes and saves the changes.

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 166

def encrypt
  encrypt_attributes if has_encrypted_attributes?
end

#encrypt_attributes (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 187

def encrypt_attributes
  validate_encryption_allowed

  update_columns build_encrypt_attribute_assignments
end

#encrypted_attribute?(attribute_name) ⇒ Boolean

Returns whether a given attribute is encrypted or not.

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 146

def encrypted_attribute?(attribute_name)
  name = attribute_name.to_s
  name = self.class.attribute_aliases[name] || name

  return false unless self.class.encrypted_attributes&.include? name.to_sym

  type = type_for_attribute(name)
  type.encrypted? read_attribute_before_type_cast(name)
end

#validate_encryption_allowed (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/encryption/encryptable_record.rb', line 200

def validate_encryption_allowed
  raise ActiveRecord::Encryption::Errors::Configuration, "can't be modified because it is encrypted" if ActiveRecord::Encryption.context.frozen_encryption?
end