Module: Anonymizable

Defined in:
lib/anonymizable.rb,
lib/anonymizable/version.rb,
lib/anonymizable/configuration.rb

Defined Under Namespace

Classes: Configuration, ConfigurationError

Constant Summary collapse

AnonymizeError =
Class.new(StandardError)
DeleteProhibitedError =
Class.new(StandardError)
DestroyProhibitedError =
Class.new(StandardError)
VERSION =
"0.1"

Class Method Summary collapse

Class Method Details

.extended(klass) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/anonymizable.rb', line 9

def self.extended(klass)

  klass.class_eval do

    class << self
      attr_reader :anonymization_config

      def anonymizable(*attrs, &block)
        @anonymization_config ||= Configuration.new(self)
        if block
          options = attrs.extract_options!
          @anonymization_config.send(:public) if options[:public] == true
          @anonymization_config.send(:raise_on_delete) if options[:raise_on_delete] == true
          @anonymization_config.instance_eval(&block)
        else
          @anonymization_config.attributes(*attrs)
        end

        define_method(:anonymize!) do
          return false unless _can_anonymize?

          original_attributes = attributes.dup
          transaction do
            _anonymize_columns
            _anonymize_associations
            _delete_associations
            _destroy_associations
          end
          _perform_post_anonymization_callbacks(original_attributes)
          true
        end

        unless @anonymization_config.public?
          self.send(:private, :anonymize!)
        end

        if @anonymization_config.raise_on_delete?
          define_method(:delete) do
            raise DeleteProhibitedError.new("delete is prohibited on #{self}")
          end

          define_method(:destroy) do
            raise DestroyProhibitedError.new("destroy is prohibited on #{self}")
          end
        end
      end
    end

    private

      def _can_anonymize?
        if self.class.anonymization_config.guard
          if self.class.anonymization_config.guard.respond_to?(:call)
            return self.class.anonymization_config.guard.call(self)
          else
            return self.send self.class.anonymization_config.guard
          end
        end

        true
      end

      def _anonymize_columns
        nullify_hash    = self.class.anonymization_config.attrs_to_nullify.inject({}) {|memo, attr| memo[attr] = nil; memo}
        anonymize_hash  = self.class.anonymization_config.attrs_to_anonymize.inject({}) do |memo, array|
                            attr, proc = array
                            if proc.respond_to?(:call)
                              memo[attr] = proc.call(self)
                            else
                              memo[attr] = self.send(proc)
                            end
                            memo
                          end

        update_hash = nullify_hash.merge anonymize_hash

        self.class.where(id: self.id).update_all(update_hash) unless update_hash.empty?
      end

      def _anonymize_by_call
        return if self.class.anonymization_config.attrs_to_anonymize.empty?
        update_hash = self.class.anonymization_config.attrs_to_anonymize.inject({}) do |memo, array|
          attr, proc = array
          if proc.respond_to?(:call)
            memo[attr] = proc.call(self)
          else
            memo[attr] = self.send(proc)
          end
          memo
        end
        self.class.where(id: self.id).update_all(update_hash)
      end

      def _anonymize_associations
        self.class.anonymization_config.associations_to_anonymize.each do |association|
          if self.send(association).respond_to?(:each)
            self.send(association).each {|a| a.send(:anonymize!) }
          elsif self.send(association)
            self.send(association).send(:anonymize!)
          end
        end
      end

      def _delete_associations
        self.class.anonymization_config.associations_to_delete.each do |association|
          if self.send(association).respond_to?(:each)
            self.send(association).each {|r| r.delete}
          elsif self.send(association)
            self.send(association).delete
          end
        end
      end

      def _destroy_associations
        self.class.anonymization_config.associations_to_destroy.each do |association|
          if self.send(association).respond_to?(:each)
            self.send(association).each {|r| r.destroy}
          elsif self.send(association)
            self.send(association).destroy
          end
        end
      end

      def _perform_post_anonymization_callbacks(original_attributes)
        self.class.anonymization_config.post_anonymization_callbacks.each do |callback|
          if callback.respond_to?(:call)
            callback.call(original_attributes)
          else
            self.send(callback, original_attributes)
          end
        end
      end

  end

end