Skip to content

Commit

Permalink
Merge pull request #28 from optimalworkshop/platform/plat-745
Browse files Browse the repository at this point in the history
[PLAT-745] Allow a scope to be passed in as part of the configuration
  • Loading branch information
traceyn authored Apr 4, 2022
2 parents 26b2b3f + 58f91f4 commit 51873ec
Show file tree
Hide file tree
Showing 8 changed files with 354 additions and 10 deletions.
10 changes: 10 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@ AllCops:
Metrics/BlockLength:
Exclude:
- 'spec/**/*_spec.rb'
- 'spec/spec_helper.rb'

Style/Documentation:
Enabled: false

Metrics/MethodLength:
Max: 15

Layout/ArgumentAlignment:
Enabled: false

Metrics/ModuleLength:
Max: 150

Metrics/AbcSize:
Max: 18
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
deidentify (2.0.1)
deidentify (2.1.0)
rails (>= 5.0.0)

GEM
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,20 @@ Deidentify.configure do |config|
config.salt = # Your secret value
end
```

## Scope Configuration

It's possible to pass a scope into the configuration.

```ruby
Deidentify.configure do |config|
config.scope = ->(klass_or_association) { klass_or_association.where(deidentified_at: nil) }
end
```
This scope will limit what records will be deidentified.

So in this example it will not deidentify records that have already been marked as deidentified.

## Generator

This gem comes with a generator that will generate a deidentification policy module for a model. By calling
Expand Down
2 changes: 1 addition & 1 deletion deidentify.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Gem::Specification.new do |s|
s.name = 'deidentify'
s.version = '2.0.1'
s.version = '2.1.0'
s.summary = 'Deidentify a rails model'
s.description = 'A gem to allow deidentification of certain fields'
s.authors = ['Lucy Dement']
Expand Down
63 changes: 58 additions & 5 deletions lib/deidentify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ def deidentify_associations(*associations)
end

def deidentify!
scope = Deidentify.configuration.scope
return self if scope && scope.call(self.class).find_by(id: id).nil?

recursive_deidentify!(deidentified_objects: [])
end

Expand Down Expand Up @@ -105,13 +108,63 @@ def deidentify_associations!
raise Deidentify::Error, "undefined association #{association_name} in #{self.class.name} deidentification"
end

if association.collection?
send(association_name).each do |object|
object.recursive_deidentify!(deidentified_objects: @deidentified_objects)
end
scope = Deidentify.configuration.scope
if scope
deidentify_associations_with_scope!(association_name, association, scope)
else
deidentify_associations_without_scope!(association_name, association)
end
end
end

def deidentify_associations_without_scope!(association_name, association)
if association.collection?
deidentify_many!(send(association_name))
else
deidentify_one!(send(association_name))
end
end

def deidentify_associations_with_scope!(association_name, association, configuration_scope)
if association.collection?
# eg. has_many :bubbles, -> { popped }
# This will call configuration_scope.call(self.bubbles).merge(popped)
class_query = class_query(association.scope, configuration_scope, send(association_name))

deidentify_many!(class_query)
else
class_query = class_query(association.scope, configuration_scope, association.klass)

if association.has_one?
# eg. (bubble) has_one :party, -> { birthday }
# This will call configuration_scope.call(Party).merge(birthday).find_by(bubble_id: id)
deidentify_one!(class_query.find_by("#{association.foreign_key} = #{send(:id)}"))
else
send(association_name)&.recursive_deidentify!(deidentified_objects: @deidentified_objects)
# eg. belongs_to :party, -> { birthday }
# This will call configuration_scope.call(Party).merge(birthday).find_by(id: party_id)
deidentify_one!(class_query.find_by(id: send(association.foreign_key)))
end
end
end

def class_query(association_scope, configuration_scope, klass_or_association)
if association_scope.nil?
configuration_scope.call(klass_or_association)
else
# Use both the configuration scope and the scope from the association.
# Unfortunately the order here matters so something in the association_scope
# will take precedence over the configuration scope.
configuration_scope.call(klass_or_association).merge(association_scope)
end
end

def deidentify_many!(records)
records.each do |record|
record.recursive_deidentify!(deidentified_objects: @deidentified_objects)
end
end

def deidentify_one!(record)
record&.recursive_deidentify!(deidentified_objects: @deidentified_objects)
end
end
3 changes: 2 additions & 1 deletion lib/deidentify/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

module Deidentify
class Configuration
attr_accessor :salt
attr_accessor :salt, :scope

def initialize
@salt = nil
@scope = scope
end
end
end
Loading

0 comments on commit 51873ec

Please sign in to comment.