Skip to content

Conversation

@bfreese
Copy link
Collaborator

@bfreese bfreese commented Feb 3, 2023

This is just a special branch of which permits the gems usage in conjunction with Rails 7 encryption/Ruby 3 to facilitate backfill. Parts pulled from a few other forks. This facilitates the UW way of migrating off of the gem which involves the following model concern. The difference is we don't hack together our own implementation or Rails 7 encryption and get the benefit of compression (i.e. let rails do its thing)

This branch probably won't be merged. The latest usable package of this is : 3.1.0.pre.0a24053

module EncryptionMigration
  extend ::ActiveSupport::Concern

  included do
    before_validation :ensure_migration

    def ensure_migration
      self.class.ensure_migration(self)
    end
  end

  module ClassMethods
    def encryption_migration(*attributes)
      raise(ArgumentError, 'At least one attribute is required') if attributes.empty?

      @migration_columns ||= []
      @migration_columns.push(*attributes)

      define_method('encryption_needs_migration?') do |attr|
        new_value = @attributes[attr.to_s].value
        legacy_value = __send__("legacy_#{attr}")

        # somewhat hacky, but the class is private
        return true if @attributes[attr.to_s].class.to_s.match(/FromDatabase/).present? && new_value != legacy_value

        false
      end

      define_method('ensure_migration_for') do |attr|
        if encryption_needs_migration?(attr)
          @attributes.write_from_user(attr.to_s, __send__("legacy_#{attr}"))
        else
          __send__("legacy_#{attr}=", @attributes[attr.to_s].value)
        end
      end

      @migration_columns.each do |attr|
        define_method("#{attr}_migration") do
          ensure_migration_for(attr)
          @attributes[attr.to_s].value
        end

        alias_method(attr.to_s, "#{attr}_migration")
      end
    end

    def ensure_migration(model)
      @migration_columns.each { |attr| model.ensure_migration_for(attr) }
    end
  end
end

Such that given a model with attr_encrypted column of ssn, we'd adjust like so:

class InvalidSsn < ApplicationRecord
  include EncryptionMigration

  attr_encrypted :legacy_ssn, key: ENCRYPTION_KEY_SSN, attribute: :encrypted_ssn # rename to legacy_field
  encrypts :ssn # new rails encryption
  encryption_migration :ssn # migration handler

  validates :ssn, length:      { minimum: 9, maximum: 9 },
                  format:      { with: /\A\d{9}\z/ },
                  allow_blank: false
end

@bfreese bfreese self-assigned this Feb 3, 2023
@bfreese bfreese changed the title Brinaf/migrate to rails 7 ruby 3 Different approach to migration from attr_encrypted to Rails 7/Ruby 3 Feb 3, 2023
@bfreese bfreese changed the title Different approach to migration from attr_encrypted to Rails 7/Ruby 3 Different approach to migrate from attr_encrypted to Rails 7/Ruby 3 encryption Feb 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant