If you like what you see, why not recommend me on WorkingWithRails?
This Ruby on Rails plugin allows you easily generate a version of your application’s database
that does not contain any proprietary data. It “protects the innocent”.
It’s built upon the Faker gem which generates random names, email addresses,
text and more.
Have you ever wanted to demo an existing, working application without revealing
private data? Maybe you want to bring another developer on board, and you need
to give them realistic seed data.
Why not just fake this data? The more complex your app gets, the harder it
is to fake this with yaml files, or even factories. But there’s another reason:
there’s no substitute for real-world data. Any records you create by hand will
be based on your assumptions of how your app is used. Maybe you never thought
to test how your view handles a cart with zero items, for instance.
WARNING! Running the rake task below WILL change the data in your database. It
does not create a new, sanitized database. How could it? It is advised that
you copy your database to a development version, and run the rake tasks there.
In a nutshell, you need to:
- Add should_protect_as_innocent helper to your unit test (if you’re using shoulda)
- Add protection to your chosen models, choosing which fields should be protected.
- Run the rake task that will actually protect all chosen model records.
For the impatient, here’s a three step example:
# test/unit/task_test.rb class TaskTest < ActiveSupport::TestCase should_protect_the_innocent :name=>:name, :email=>:email, :age=>:number, :description=>:text end
# app/models/task.rb class Task < ActiveRecord::Base protects_the_innocent :name=>:name, :email=>:email, :age=>:number, :description=>:text end
# command line rake protect:all
For a more in-depth understanding, read on.
There is a test helper available if you use shoulda. Use the example above.
It takes the same parameters as your call to protects_the_innocent
in the model itself.
In order to protect a model, call protects_the_innocent with a hash of field
names you want to protect, along with the data type. View the example above.
Here are the available data types:
data type | description | example output |
---|---|---|
:company | company name | Kuphal and Sons |
:catch phrase | company slogan | Mandatory multimedia migration |
:bs | a short, made-up sentence. | iterate visionary methodologies |
:name | person’s full name | Domenic Bergnaum |
:first_name | person’s first name only | Domenic |
:last_name | person’s last name only | Bergnaum |
:username | username | marcus.bechtelar |
email address | nora_koepp@streichkohler.uk | |
:phone | phone number | 902-697-2898 x7579 |
:ip | ip address | 10.6.157.23 |
:domain | domain (url) | bahringerpagac.padberg.ca |
:address | street address | 521 Jakayla Island |
:city | city | East Vallieberg |
:state | state | Delaware |
:state_abbr | state abbreviation | MD |
:zip | zip | 32342-8723 |
:word | one latin-esque word | eum |
:words, :string | three latin-esque words | ab quia esse |
:sentence | one latin-esque sentence | Praesentium impedit mollitia deleniti officiis cum numquam quasi aperiam. |
:sentences | three latin-esque sentences | Numquam laboriosam placeat similique quis qui. Quasi voluptatum quis omnis unde. Ut quo voluptatem ut. |
:paragraph, :text | one latin-esque paragraph | Molestiae aspernatur est ipsum dolores in suscipit. Recusandae eaque alias occaecati aut earum adipisci nostrum. Eligendi eum et doloremque. Delectus maxime est a nihil aperiam nemo alias qui. |
:paragraphs | three latin-esque paragraphs | Eos et esse consequatur quod labore debitis dicta. Quis placeat minus enim natus. Provident nesciunt aut nostrum voluptate molestiae omnis. Minus nostrum quia velit corporis consectetur sed nulla. Quidem doloribus aut ut nam velit quos omnis. Illo labore consectetur culpa nihil quibusdam. Facilis et suscipit ipsam totam fugit. Ut et et distinctio voluptatum. Non temporibus quas velit delectus eligendi accusantium illo. Illo in sunt adipisci pariatur quis enim voluptatum omnis. Ullam possimus ut odio. |
:nil | ruby’s nil value | nil |
:number | any number | This is cool: it will return a random number, but close enough to the original to be believable in almost any circumstance. |
There are also these special, custom data types. I’ll show you example input
instead of example output, since they’re more complex:
data type | description | example usage |
---|---|---|
lambda{|model| …} | Any anonymous function you wish to pass in. The parameter is the object being protected. | lambda{|x| x.user.display_name} |
any static value | You can pass in any static value. | “turkey” |
You can protect all the models at once, only the ones you include, or all but the ones you exclude, respectively:
# Assume you have the following models: Client, Task, CustomerProfile, and Comment # protect all four models, alphabetically rake protect:all # protect only Client, Task, and CustomerProfile models in the order listed rake protect:only MODELS=Client,Task,CustomerProfile # protect all models except Comment, in alphabetical order rake protect:except MODELS=Comment
Models can be listed in camelCase or under_scored form.
Sometimes the fake data in one model will depend on the fake data already created
in another model. In this case, order is important. Models are protected
alphabetically by name, by default. You can create a short custom rake task to
specify any order you want, to save future typing:
# lib/tasks/custom_protection.rake namespace :protect do desc "Protect models in the order I choose" task :sorted => :environment do ENV['MODELS'] = "task,client" Rake::Task["protect:only"].invoke end end
All we’re doing here is calling the protect:only task that already exists. We’re
setting the MODELS environment variable to a comma-separated list of models, in
the order we choose.
Sometimes certain fields depend on others when a record is in the act of being
protected. Let’s say, for whatever reason, you have first_name, last_name,
and full_name attributes. The full name should obviously be a composite of the
first and last names, but that will only work if we know full_name is determined
last. On top of that, we need to pass a function into our protection call that
combines first and last names into one:
protects_the_innocent [ [:first_name, :first_name], [:last_name, :last_name], [:full_name, lambda{|x| "#{x.first_name} #{x.last_name}"}] ]
We’ve done two things here. First, we used a 2-dimensional array instead of a
hash, because it preserves its order. protects_the_innocent doesn’t care, because
it simply calls .first and .last on each set of values.
Second, we’ve passed in an anonymous function, with the parameter being the object
currently undergoing protection. We use it to set the full name to a combination
of first and last name.
- expanded syntax to allow greater control over generated content:
- numbers:
- min value
- max value
- list of acceptable values
- words, sentences, and paragraphs:
- specified number of items
- maximum length of generated string
- all string types
- flag for unique value
- new value that is guaranteed to be different from original
- numbers:
Copyright © 2009 Jaime Bellmyer, released under the MIT license