BetterSeeder
BetterSeeder is a Rails gem designed to simplify and centralize your application's seeding process. It offers a flexible system to generate dynamic data, validate it using Dry-schema, enforce uniqueness constraints, load data into the database, and export it in various formats (SQL, CSV, JSON). The configuration is managed through a Rails initializer, while model-specific logic is defined in dedicated structure files.
Statistics
Below are two images displaying key statistics from the seeding process:
-
Initial Generation Statistics:
This chart represents metrics from the very first generation run.
-
Reload Data Statistics:
This chart shows the metrics after reloading data (from the SQL file) into the database.
Features
-
Dynamic Data Generation
Define custom data generators for each model in dedicated structure files. -
Validation and Uniqueness
Validate generated records using Dry-schema and enforce uniqueness constraints across one or multiple columns. -
Loading & Exporting
Load generated data directly into your database—supporting parent/child relationships—and export the data as a single SQL INSERT statement, CSV, or JSON file. -
Centralized Configuration
Customize settings such aslog_language
,structure_path
, andpreload_path
via a Rails initializer. If no initializer is provided, default settings apply. -
Initializer Installation
An install method creates the necessary initializer file in your Rails application to streamline setup. -
Rails Generator
A custom Rails generator scaffolds a structure file template for your models, ensuring a consistent configuration format. -
Child Record Generation
Now, BetterSeeder supports generating multiple child records per parent record. In your model’s seed configuration, you can define achilds
section that specifies the number of child records to generate for each parent, along with attribute arrays to assign distinct values for each child. This allows for a total record count equal to (parent count) × (childs count). -
Preflight Data
You can now define apreflight
method in your structure file. The records returned by this method are inserted first before generating any additional records, ensuring that specific data is loaded as part of the seeding process. The total record count (defined inseed_config[:count]
) includes these preflight records.
Installation
Add the gem to your Gemfile:
gem 'better_seeder'
Then run:
bundle install
Configuration
BetterSeeder uses a centralized configuration defined in BetterSeeder.configuration
. You can override the default settings by creating an initializer. For example, create a file:
# config/initializers/better_seeder.rb
require 'better_seeder'
BetterSeeder.configure do |config|
config.log_language = :en
config.structure_path = Rails.root.join('db', 'seed', 'structure')
config.preload_path = Rails.root.join('db', 'seed', 'preload')
end
If these values are set in the initializer, they will be used; otherwise, the gem will use its default values.
Initializer Installation
To streamline the setup, execute the following command in your Rails console:
BetterSeeder.install
This command creates (if not already present) the file config/initializers/better_seeder.rb
with the necessary configuration.
Structure Files
For each model, create a structure file that centralizes the logic for generating, validating, and configuring seed data. Each structure file should include:
-
structure
Returns a hash where each key is an attribute and its value is an array in the format[type, lambda_generator]
. -
seed_schema
(Optional)
Defines a Dry-schema for validating generated records. -
seed_config
Returns a hash with model-specific seeding settings:-
file_name
: The output file name (without extension) -
columns: { excluded: [...] }
: Columns to exclude from the generated data -
generate_data
: Boolean flag indicating whether to generate data dynamically (if false, existing records are used) -
count
: The number of parent records to generate (default: 10) -
load_data
: Boolean flag indicating whether the generated records should be inserted into the database -
parent
: For child models, specifies the parent model(s) used for injecting foreign keys -
childs
(Optional): A hash to define child record generation:-
count
: The number of child records to generate for each parent. -
attributes
: A hash mapping attribute names to an array of values. Each child record will receive a distinct value from the provided array.
-
-
-
preflight
(Optional)
If defined, this method should return an array of records to be inserted before generating dynamic records. These preloaded records count toward the total defined bycount
. -
unique_keys
(Optional)
Returns an array of column groups (each group is an array of symbols) that must be unique. For example:def self.unique_keys [[:email], [:first_name, :last_name]] end
Example Structure File
# db/seed/structure/my_namespace/my_model_structure.rb
module MyNamespace
class MyModelStructure < BetterSeeder::StructureBase
def self.structure
{
name: [:string, -> { FFaker::Name.name }],
email: [:string, -> { FFaker::Internet.email }],
created_at: [:datetime, -> { Time.zone.now }]
}
end
def self.seed_schema
Dry::Schema.Params do
required(:name).filled(:string)
required(:email).filled(:string)
required(:created_at).filled(:time)
end
end
def self.seed_config
{
file_name: 'my_model_seed',
columns: { excluded: [:id, :updated_at] },
generate_data: true,
count: 50,
load_data: true,
parents: [
{ model: ::MyNamespace::MyModelParent, column: :column_id }
],
childs: {
count: 3,
attributes: {
some_attribute: ['value1', 'value2', 'value3']
}
}
}
end
def self.preflight
[{ name: 'preloaded record', email: 'preloaded@example.com', created_at: Time.zone.now }]
end
def self.unique_keys
[[:email]]
end
end
end
How It Works
When you call BetterSeeder.magic
with a configuration that contains an array of model names (as strings), the gem will:
-
Load Structure Files
Retrieve the corresponding structure file from the directory defined byBetterSeeder.configuration.structure_path
for each model. -
Retrieve Seeding Configurations
Invoke the model'sseed_config
method to obtain its specific settings. -
Preflight Data
If apreflight
method is defined in the structure file, its returned records will be inserted first. These records count toward the total number of records defined inseed_config[:count]
. -
Generate or Retrieve Records
Use thestructure
method to generate data dynamically (or fetch existing records) and validate them usingseed_schema
if defined. Uniqueness is enforced viaunique_keys
. -
Handle Parent/Child Relationships
Automatically inject foreign keys into child models using records from parent models. With the new functionality, if achilds
configuration is present, the gem generates child records for each parent record. For example, ifcount
is set to 200 andchilds[:count]
is set to 2, a total of 400 records will be generated. Each child record receives distinct attribute values from the specified arrays. -
Load and Export Data
If enabled (load_data: true
), the generated records are inserted into the database and exported in the specified format (SQL, CSV, or JSON). Export files are saved in the directory specified byBetterSeeder.configuration.preload_path
.
Example Usage
BetterSeeder.magic(
{
configurations: { export_type: :sql },
data: [
'MyNamespace::MyModel',
'OtherNamespace::OtherModel'
]
}
)
Rails Generator
A custom Rails generator is available to scaffold a structure file template for your models. Execute the following command:
rails generate better_seeder:structure MyNamespace::MyModel
This command creates a structure file template in the appropriate subdirectory under db/seed/structure
. The generated template includes placeholders for:
- Attribute generators (via the
structure
method) - Validation schema (via the
seed_schema
method) - Seeding configuration (via the
seed_config
method) - Uniqueness constraints (via the
unique_keys
method)
Example Generated Template
module MyNamespace
class MyModelStructure < BetterSeeder::StructureBase
def self.structure
{
attribute_name: [:string, -> { "your value" }]
}
end
def self.seed_schema
Dry::Schema.Params do
required(:attribute_name).filled(:string)
end
end
def self.seed_config
{
file_name: 'my_model_seed',
columns: { excluded: [] },
generate_data: true,
count: 10,
load_data: true,
parent: nil
}
end
def self.unique_keys
[]
end
end
end
This generator ensures a consistent structure for your seeding configuration across models.
Contact & Feature Requests
For suggestions, bug reports, or to report new feature requests, please reach out via email at: alessio.bussolari@pandev.it.
Upcoming Features
The development team is continuously enhancing BetterSeeder. Current efforts include:
- Additional Export Formats: Expanding beyond SQL, CSV, and JSON to offer more options.
- Enhanced Rails Associations Integration: Improving support for complex parent/child relationships.
- Expanded Configuration Options: Providing more granular control over the seeding process.
- Performance Optimizations: Refining data generation algorithms for faster processing.
Conclusion
BetterSeeder provides a modular, configurable, and extensible system for seeding your Rails application's data. Its key benefits include:
- Centralized Configuration: Manage settings through a simple Rails initializer.
- Modular Structure Files: Define data generation, validation, and configuration logic on a per-model basis.
- Seamless Data Handling: Efficiently generate, validate, load, and export seed data while supporting complex relationships—now with enhanced child record generation for a more realistic data model.
For further details or to contribute, please refer to the official repository or documentation.