class Anony::Strategies::Overwrite
The interface for configuring a field-level strategy. All of the methods here are made available inside the `overwrite { … }` block:
@example
anonymise do overwrite do nilable :first_name email :email_address with_strategy(:last_name) { "last-#{id}" } end end
Attributes
A hash containing the fields and their anonymisation strategies.
Public Class Methods
@!visibility private
# File lib/anony/strategies/overwrite.rb, line 22 def initialize(model_class, &block) @model_class = model_class @anonymisable_fields = {} instance_eval(&block) if block end
Public Instance Methods
Apply the Overwrite
strategy on the model instance, which applies each of the configured transformations and updates the :anonymised_at field if it exists.
@param [ActiveRecord::Base] instance An instance of the model
# File lib/anony/strategies/overwrite.rb, line 47 def apply(instance) if !@anonymisable_fields.key?(:anonymised_at) && @model_class.column_names.include?("anonymised_at") current_datetime(:anonymised_at) end @anonymisable_fields.each_key do |field| anonymise_field(instance, field) end result_fields = instance.changes.keys.map(&:to_sym).reject { |s| s == :anonymised_at } instance.save! Result.overwritten(result_fields) end
Helper method to use the :hex strategy @param [Array<Symbol>] fields A list of one or more fields to apply this strategy to. @see Strategies::OverwriteHex
@example
hex :first_name
# File lib/anony/strategies/overwrite.rb, line 112 def hex(*fields, max_length: 36) with_strategy(Strategies::OverwriteHex.new(max_length), *fields) end
Configure a list of fields that you don't want to anonymise.
@param [Array<Symbol>] fields The fields to ignore @raise [ArgumentError] If trying to ignore a field which is already globally
ignored in Anony::Config.ignores
@example
ignore :external_system_id, :externalised_at
# File lib/anony/strategies/overwrite.rb, line 124 def ignore(*fields) already_ignored = fields.select { |field| Config.ignore?(field) } if already_ignored.any? raise ArgumentError, "Cannot ignore #{already_ignored.inspect} " \ "(fields already ignored in Anony::Config)" end no_op(*fields) end
Check whether the combination of field-level rules is valid
# File lib/anony/strategies/overwrite.rb, line 32 def valid? validate! true rescue FieldException false end
# File lib/anony/strategies/overwrite.rb, line 39 def validate! raise FieldException, unhandled_fields if unhandled_fields.any? end
Configure a custom strategy for one or more fields. If a block is given that is used as the strategy, otherwise the first argument is used as the strategy.
@param [Proc, Object] strategy Any object which responds to
`.call(previous_value)`. Not used if a block is provided.
@param [Array<Symbol>] fields A list of one or more fields to apply this strategy to. @param [Block] &block A block to use as the strategy. @yieldparam previous [Object] The previous value of the field @yieldreturn [Object] The value to set on that field. @raise [ArgumentError] If the combination of strategy, fields and block is invalid. @raise [DuplicateStrategyException] If more than one strategy is defined for the same field.
@example With a named class
class Reverse def self.call(previous) previous.reverse end end with_strategy(Reverse, :first_name)
@example With a constant value
with_strategy({}, :metadata)
@example With a block
with_strategy(:first_name, :last_name) { |previous| previous.reverse }
# File lib/anony/strategies/overwrite.rb, line 90 def with_strategy(strategy, *fields, &block) if block fields.unshift(strategy) strategy = block end fields = fields.flatten raise ArgumentError, "Block or Strategy object required" unless strategy raise ArgumentError, "One or more fields required" unless fields.any? guard_duplicate_strategies!(fields) fields.each { |field| @anonymisable_fields[field] = strategy } end
Private Instance Methods
# File lib/anony/strategies/overwrite.rb, line 146 def anonymise_field(instance, field) return unless @model_class.column_names.include?(field.to_s) strategy = @anonymisable_fields.fetch(field) current_value = instance.read_attribute(field) instance.write_attribute(field, anonymised_value(instance, strategy, current_value)) end
# File lib/anony/strategies/overwrite.rb, line 155 def anonymised_value(instance, strategy, current_value) if strategy.is_a?(Proc) instance.instance_exec(current_value, &strategy) elsif strategy.respond_to?(:call) strategy.call(current_value) else strategy end end
# File lib/anony/strategies/overwrite.rb, line 165 def guard_duplicate_strategies!(fields) defined_fields = @anonymisable_fields.keys duplicate_fields = defined_fields & fields raise DuplicateStrategyException, duplicate_fields if duplicate_fields.any? end
# File lib/anony/strategies/overwrite.rb, line 135 def unhandled_fields anonymisable_columns = @model_class.column_names.map(&:to_sym). reject { |c| Config.ignore?(c) }. reject { |c| c == :anonymised_at } handled_fields = @anonymisable_fields.keys anonymisable_columns - handled_fields end