Anonymizable adds the ability to anonymize or delete data in your ActiveRecord models. A good use case for this is when you want to remove user accounts but for statistical or data integrity reasons you want to keep the actual records in your database.
Supported Ruby/Rails Versions
Anonymizer supports all 2.x versions of Ruby and all Rails versions between 3.2.x and 4.x.
Installation
gem 'anonymizable'
and run bundle install
from your shell.
Usage
Nullification
class User < ActiveRecord::Base
anonymizable do
attributes :first_name, :last_name
end
end
This adds an instance method User#anonymize!
which in this case just nullifies the first_name
andlast_name
database columns.
The anonymize!
method is defined as private by default, but you can make it public by passing the public
option:
anonymizable public: true do
attributes :first_name, :last_name
end
Anonymization
By passing to attributes
a hash as the last argument, you can anonymize columns using a Proc or instance method.
anonymizable public: true do
attributes :first_name, :last_name,
email: Proc.new { |u| "anonymized.user.#{u.id}@foobar.com" },
password: :random_password
end
In this example, the email
column will be anonymized by calling the block and passing the User
object. The password
column will be anonymized using the return value of User#random_password
, which can be defined as either a public or private instance method. The user object is not passed as an argument in this case, but can be accessed by self
.
Associations
ActiveRecord associations can either be anonymized, destroyed, or deleted.
anonymizable public: true do
attributes :first_name, :last_name,
email: Proc.new { |u| "anonymized.user.#{u.id}@foobar.com" },
password: :random_password
associations do
anonymize :posts, :comments
delete :avatar, :likes
destroy :images
end
end
In the example above, the anonymize!
method will be called on each Post
and Comment
association. As such, anonymization must be defined on both of these classes:
class Post < ActiveRecord::Base
anonymizable :user_id
end
class Comment < ActiveRecord::Base
anonymizable :user_id
end
In this case, the user_id
column is nullified on any of the user's posts or comments.
All operations on columns and attributes are performed in a database transaction which will rollback all changes if an error occurs during anonymization.
Guards
You can declare a Proc or method to use as a guard against anonymization. If the Proc or method returns ruby false
or ruby nil
, anonymization will short circuit.
anonymizable public: true do
only_if :can_anonymize?
attributes :first_name, :last_name,
email: Proc.new { |u| "anonymized.user.#{u.id}@foobar.com" },
password: :random_password
associations do
anonymize :posts, :comments
delete :avatar, :likes
destroy :images
end
end
def can_anonymize?
!admin?
end
Preventing Deletion
You can prohibit the deletion of objects on which anonymizable is configured by passing the raise_on_delete
option:
anonymizable raise_on_delete: true do
attributes :first_name, :last_name,
email: Proc.new { |u| "anonymized.user.#{u.id}@foobar.com" },
password: :random_password
associations do
anonymize :posts, :comments
delete :avatar, :likes
destroy :images
end
end
> user.delete
Anonymizable::DeleteProhibitedError: destroy is prohibited on #<User:0x007f8d125e4948>
> user.destroy
Anonymizable::DestroyProhibitedError: destroy is prohibited on #<User:0x007f8d125e4948>
Callbacks
You can declare callbacks that run after anonymization is complete.
anonymizable public: true do
attributes :first_name, :last_name,
email: Proc.new { |u| "anonymized.user.#{u.id}@foobar.com" },
password: :random_password
associations do
anonymize :posts, :comments
delete :avatar, :likes
destroy :images
end
after :email_admin, Proc.new { |original_attrs| log("Attributes changed: #{original_attrs}") }
end
Each method or Proc is passed the value of the object's pre-anonymization attributes as a hash. You would define a method on ```User`` that receives the attribute hash:
def email_admin(original_attributes)
AdminMailer.user_anonymized(original_attributes["email"])
end
It is worth noting that these callbacks are run after the database transaction commits, so an error in a callback does not trigger a database rollback.
Short Syntax
As intimated in the Post
and Comment
examples above, you can call anonymize
without a block, but rather just with an array of columns to nullify and/or anonymization hash. In this case the Model#anonymize!
will be private.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.