DirtySeed
🌱 Populate the database with records matching associations and validations in order to quickly test the application rendering.
Installation
Add this line to your application's Gemfile:
gem 'dirty_seed', '~> 0.2.1'
And then execute:
$ bundle
Usage
Once you've installed the gem, you can use the dedicated task.
To seed dirty data, run:
$ rake dirty_seed:seed
This will create 10
records for each model inheriting from ApplicationRecord
.
You can change the number of records to seed by adding a COUNT
variable:
$ rake dirty_seed:seed COUNT=42
Instance that cannot be saved are simply ignored.
For each model, the number of created records and the recurrent errors are printed out:
rake dirty_seed:seed COUNT=15
User
created: 15
Article
created: 0
errors: Title should contains the user name and the current date
Database population
For each model inheriting from ApplicationRecord
, records are created.
Models are sorted by their dependency to each others (through a belongs_to
association) to ensure that some records exist before seeding an instance that requires one.
For instance, given the following models, the order of seeding will be User
, Article
and Notification
:
# app/models/article
class Article
belongs_to :user
has_many :notifications, as: :notifiable
end
class User
has_many :articles
has_many :notifications, as: :notifiable
end
class Notification
belongs_to :notifiable, polymorphic: true
end
Value assignment
A value is assigned for each attribute, depending on its type.
Special types like json
, jsonb
and array
are treated.
For instance, given the following schema:
# db/schema.rb
create_table 'things' do |t|
t.binary 'a_binary'
t.boolean 'a_boolean'
t.date 'a_date'
t.datetime 'a_datetime'
t.decimal 'a_decimal'
t.integer 'an_integer'
t.float 'a_float'
t.string 'a_string'
t.text 'a_text'
t.time 'a_time'
t.json 'a_json'
t.text[] 'an_array'
end
...then a dirty seeded thing
looks like:
{
a_binary: '13',
a_boolean: false,
a_date: Wed, '02 Dec 2020',
a_datetime: 'Sun, 08 Nov 2020 03:01:34 UTC +00:00',
a_decimal: 19.8812490973183,
an_integer: 6,
a_float: 28.825997012616263,
a_string: 'Maxime eum ratione ab quod nihil.',
a_text: 'Autem non in est dolore.',
a_time: 'Sat, 01 Jan 2000 09:31:22 UTC +00:00',
a_json: { 'Autem': 'Dolore', 'Lorem': 'Nihil' },
an_array: ['Autem', 'Dolore', 'Nihil'],
}
Ignored attributes
Some "special" attributes are not getting a value because:
- Rails assigns it (STI type...);
- or the RDBMS (PostgreSQL, SQLite...) assigns it;
- or it is used in specific cases (authentication...).
These attributes are currently:
id
created_at
updated_at
-
type
(for STI) -
encrypted_password
(authentication usage) -
reset_password_token
(authentication usage) -
reset_password_sent_at
(authentication usage) -
remember_created_at
(authentication usage)
Associations
For attributes related to an association, an instance matching the belongs_to
is assigned.
Polymorphic associations work too and only an instance of a model that has_one
or has_many
of this association can be assigned.
For instance, given the following schema:
# schema.rb
create_table :notifications do |t|
t.references :thing
t.references :notifiable, polymorphic: true, null: false
t.references :foo, null: false, foreign_key: { to_table: :things }
end
...and the models:
# app/models/notification.rb
class Notification < ApplicationRecord
belongs_to :notifiable, polymorphic: true
belongs_to :thing
belongs_to :bar, class_name: 'Thing', foreign_key: :foo_id
end
# app/models/user.rb
class User < ApplicationRecord
has_many :notifications, as: :notifiable
end
...then a dirty seeded notification
looks like:
{
:thing_id => 42,
:notifiable_type => 'User',
:notifiable_id => 6,
:foo_id => 75
}
notification.notifiable.class # User
notification.thing.class # Thing
notification.bar.class # Thing
Validations
For attributes requiring validations, assigned value is adapted.
Currently, the following validations are treated:
absence
format: { with: regex }
inclusion: { in: [x, y] }
length: { minimum: x }
length: { maximum: x }
length: { in: x..y }
length: { is: x }
numericality: { greater_than: x }
numericality: { greater_than_or_equal_to: x }
numericality: { lesser_than: x }
numericality: { lesser_than_or_equal_to: x }
numericality: { in: x..y }
uniqueness
Attribute with an enum
are treated too.
Custom validations are not inspected.
Meaning detection
Some string attribute meanings are guessed by name: email
, first_name
, latitude
...
Values are then built with the faker
gem.
For instance, given the following schema:
# db/schema.rb
create_table "users" do |t|
t.string "first_name"
t.string "last_name"
t.string "address"
t.string "city"
t.string "country"
t.string "email"
t.string "password"
t.string "phone"
t.string "username"
# ...
end
...then a dirty seeded user
looks like:
{
first_name: 'Emory',
last_name: 'Franecki',
address: '843 Schneider Squares, Port Olenmouth, TN 12657',
city: 'Torpshire',
country: 'United Arab Emirates',
email: 'scottie_friesen@example.net',
password: 'ZkUtNtFg4L',
phone: '(814) 382-6102 x036',
username: 'ernestine_rau',
# ...
}
The current attribute names treated this way are:
address
city
color
colour
country
currency
description
email
first_name
firstname
last_name
lastname
lat
latitude
lng
locale
longitude
middlename
middle_name
password
phone
phone_number
reference
title
user_name
username
uuid
License
The gem is available as open source under the terms of the MIT License.
Next features and improvements
- Add specs to validate all specific errors rescue.
- Manage validations on dates and times.
- Detect more meaningful attributes.
- Detect more protected attributes (attributes to ignore).
- Add a configuration system to define how to seed: excluded models, default values, faker method...