-
Notifications
You must be signed in to change notification settings - Fork 1
Build ka scrub types #1
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
Gemfile.lock | ||
.idea |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,33 +16,44 @@ gem 'acts_as_scrubbable' | |
|
||
## Usage | ||
|
||
Simple add the configuration for your fields that map directly to your columns | ||
Add the configuration for your fields that map directly to your columns and a scrub_type | ||
for those columns. | ||
|
||
Default Scrub types include: | ||
- `scrub` - scrub the field's value based on it's name or mapping (see mapping case below) | ||
- `skip` - do not scrub the field's value | ||
- `wipe` - set the field's value to nil on scrub | ||
- `sterilize` - delete all records for this model on scrub | ||
|
||
```ruby | ||
class User < ActiveRecord::Base | ||
class ScrubExample < ActiveRecord::Base | ||
... | ||
|
||
acts_as_scrubbable :first_name, :last_name | ||
acts_as_scrubbable :scrub, :first_name # first_name will be random after `scrub!` | ||
acts_as_scrubbable :skip, :middle_name # middle_name will be original value after `scrub!` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "will be unchanged"? |
||
acts_as_scrubbable :wipe, :last_name # last_name will be `nil` after `scrub!` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't love the DSL calling the same method 3 times, but otherwise the concept is sound. is there an easy way to come up with a way to create one dataset for the complete class configuration? maybe something like: acts_as_scrubbable scrub: [:first_name, lat: :latitude],
skip: [:middle_name],
wipe: [:last_name] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also, this technique would need to be paired with some validation that when any fields are configured to be scrubbed, skipped or wiped, that all fields are configured, right? otherwise 'skip' and literally skipping are the same... or is that something AnonCat would do? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ahh, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. on further thought, it'd be really cool to be able to define scrub procs here, too. e.g.: acts_as_scrubbable scrub: [gender: -> { %w(M F).sample }] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fan of the array update and would push for going more in that direction. also agree that defining scrub procs would be neat (maybe a well placed went with wipe for the theme :D, also thought it left room for fancier wiping (empty string?). Fine with nullify |
||
|
||
|
||
# optionally you can add a scope to limit the rows to update | ||
scope :scrubbable_scope, -> { where(some_value: true) } | ||
|
||
... | ||
end | ||
``` | ||
|
||
class SterilizeExample < ActiveRecord::Base | ||
acts_as_scrubbable :sterilize # table will contain no records after `scrub!` | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cool |
||
|
||
``` | ||
|
||
Incase the mapping is not straight forward | ||
|
||
```ruby | ||
class Address | ||
acts_as_scrubbable :lng => :longitude, :lat => :latitude | ||
acts_as_scrubbable :scrub, :lng => :longitude, :lat => :latitude | ||
end | ||
``` | ||
|
||
|
||
### To run | ||
|
||
The confirmation message will be the db host | ||
|
@@ -75,22 +86,31 @@ If you want to limit the classes you to be scrubbed you can set the `SCRUB_CLASS | |
rake scrub SCRUB_CLASSES=Blog,Post | ||
``` | ||
|
||
If you want to skip the afterhook | ||
If you want to skip the beforehook | ||
|
||
``` | ||
rake scrub SKIP_AFTERHOOK=true | ||
rake scrub SKIP_BEFOREHOOK=true | ||
``` | ||
|
||
If you want to skip the afterhook | ||
|
||
``` | ||
rake scrub SKIP_AFTERHOOK=true | ||
``` | ||
|
||
### Extending | ||
|
||
You may find the need to extend or add additional generators or an after_hook | ||
You may find the need to extend or add additional generators or an before_hook/after_hook | ||
|
||
```ruby | ||
ActsAsScrubbable.configure do |c| | ||
c.add :email_with_prefix, -> { "prefix-#{Faker::Internet.email}" } | ||
|
||
c.before_hook do | ||
puts "Running before scrub" | ||
raise "Don't run in production" if Rails.env.production? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will the env ever be production? the other PR assumes it is always development in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. on further thought, this suggestion makes no sense. it's good as-is. |
||
end | ||
|
||
c.after_hook do | ||
puts "Running after commit" | ||
ActiveRecord::Base.connection.execute("TRUNCATE some_table") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,11 +11,18 @@ module ActsAsScrubbable | |
autoload :Scrub | ||
autoload :VERSION | ||
|
||
|
||
def self.configure(&block) | ||
yield self | ||
end | ||
|
||
def self.before_hook(&block) | ||
@before_hook = block | ||
end | ||
|
||
def self.execute_before_hook | ||
@before_hook.call if @before_hook | ||
end | ||
|
||
def self.after_hook(&block) | ||
@after_hook = block | ||
end | ||
|
@@ -45,16 +52,18 @@ def self.scrub_map | |
:state_abbr => -> { Faker::Address.state_abbr }, | ||
:state => -> { Faker::Address.state }, | ||
:city => -> { Faker::Address.city }, | ||
:full_address => -> { Faker::Address.full_address }, | ||
:latitude => -> { Faker::Address.latitude }, | ||
:longitude => -> { Faker::Address.longitude }, | ||
:username => -> { Faker::Internet.user_name }, | ||
:boolean => -> { [true, false ].sample }, | ||
:school => -> { Faker::University.name } | ||
:school => -> { Faker::University.name }, | ||
:bs => -> { Faker::Company.bs }, | ||
:phone_number => -> { Faker::PhoneNumber.phone_number } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i personally found using these built-ins just some of the time seemed confusing, so didn't use them at all. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. after looking at the other PR i see you used |
||
} | ||
end | ||
end | ||
|
||
|
||
ActiveSupport.on_load(:active_record) do | ||
extend ActsAsScrubbable::Scrubbable | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,29 @@ | ||
module ActsAsScrubbable | ||
module Scrub | ||
|
||
def scrub! | ||
return unless self.class.scrubbable? | ||
|
||
run_callbacks(:scrub) do | ||
if self.class.sterilizable? | ||
self.destroy! | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also worried that calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in the |
||
next | ||
end | ||
|
||
_updates = {} | ||
|
||
scrubbable_fields.each do |_field, value| | ||
unless self.respond_to?(_field) | ||
raise ArgumentError, "#{self.class} do not respond to #{_field}" | ||
end | ||
next if self.send(_field).blank? | ||
next if self.send(_field).blank? || value == :skip | ||
|
||
if ActsAsScrubbable.scrub_map.keys.include?(value) | ||
_updates[_field] = ActsAsScrubbable.scrub_map[value].call | ||
elsif value == :wipe | ||
_updates[_field] = nil | ||
else | ||
puts "Undefined scrub: #{value} for #{self.class}#{_field}" | ||
end | ||
puts "Undefined scrub: #{value} for #{self.class}.#{_field}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
end | ||
end | ||
|
||
self.update_columns(_updates) unless _updates.empty? | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,35 @@ | ||
module ActsAsScrubbable | ||
module Scrubbable | ||
|
||
|
||
def scrubbable? | ||
false | ||
end | ||
|
||
def acts_as_scrubbable(scrub_type=:scrub, *scrubbable_fields, **mapped_fields) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't think you can have default values to the left of var-args? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can! it just isn't respected. Was having trouble finding a good way to fit in the scrub_type while not creating too breaking of a change. I think the approach you listed at the top is better (kwargs all the way, arrays of symbols or kwargs as values |
||
unless self.respond_to?(:scrubbable_fields) | ||
class_attribute :scrubbable_fields | ||
self.scrubbable_fields = {} | ||
end | ||
|
||
def acts_as_scrubbable(*scrubbable_fields, **mapped_fields) | ||
|
||
class_attribute :scrubbable_fields | ||
|
||
self.scrubbable_fields = {} | ||
scrubbable_fields.each do |_field| | ||
self.scrubbable_fields[_field] = _field | ||
unless self.respond_to?(:sterilizable?) | ||
class_attribute :sterilizable | ||
self.sterilizable = scrub_type == :sterilize | ||
end | ||
|
||
mapped_fields.each do |_field| | ||
self.scrubbable_fields[_field.first] = _field.last | ||
scrubbable_fields.each do |field_name| | ||
self.scrubbable_fields[field_name] = scrub_type == :scrub ? field_name : scrub_type | ||
end | ||
|
||
mapped_fields.each { |field_name, field_type| self.scrubbable_fields[field_name] = field_type } | ||
|
||
class_eval do | ||
define_callbacks :scrub | ||
|
||
def self.scrubbable? | ||
true | ||
end | ||
|
||
end | ||
|
||
include Scrub | ||
end | ||
|
||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
ActiveRecord::Schema.define(version: 20150421224501) do | ||
|
||
create_table "scrubbable_models", force: true do |t| | ||
t.string "first_name" | ||
t.string "middle_name" | ||
t.string "last_name" | ||
t.string "address1" | ||
t.string "lat" | ||
end | ||
|
||
create_table "sterilizable_models", force: true do |t| | ||
t.string "irrelevant" | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i feel like "faker-generated" is clearer than "random". i had to look at the source code to figure that out.