SeedHelper
SeedHelper is a small gem I created while I was working on various projects with terrible Seed files.
Purpose
The goal of SeedHelper is to provide some commonly required functionality to make creating Seed files easier.
Dependencies
SeedHelper uses the colorize gem to present output.
Example: Seed implementation
I use rake tasks to create my seed data. That way you can easily run individual tasks for seeding specific pieces of data.
Using SeedHelper, a seed task might look like:
# in lib/tasks/seeds/create_roles.rake
SeedHelper.create_seed_task(:create_roles) do
["Admin", "Regular"].each do |role_name|
# Will print out a red message if Role fails to save
# Will print out a green message is Role succesfully creates
# Will print out a cyan message if Role already exists
SeedHelper.find_or_create_resource(Role, {name: role_name})
end
end
# in lib/tasks/seeds/create_users.rake
include SeedHelper
# Specify a dependency on roles, so that running this task will first
# run the create_roles task
SeedHelper.create_seed_task(:create_users, [:create_roles]) do
[
["[email protected]", Role.admin],
["[email protected]", Role.other]
].each do |email, role_name|
role = Role.find_by(name: role_name)
admin = SeedHelper.find_or_create_resource(User, {email: email, role: role_name})
end
end
By default, the .find_or_create_resource
method uses the hash you provide it to find a User with those attributes. It can then determine whether or not it needs to create a new User.
This becomes problematic when we have a lot of fields, since we don't want to try and identify a User by some of those fields - password, for example.
In that case, we can pass through a third argument of all those additional fields:
SeedHelper.find_or_create_resource(User, {email: email}, {password: "password", role: role_name})
Example: Using FactoryGirl for a single object
Sometimes you'll want to create an object using FactoryGirl. You can pass a block to .find_or_create_resource
to achieve this. EG:
SeedHelper.find_or_create_resource(User, {email: "[email protected]"}, {password: "Alligator8"}) do |attributes|
FactoryGirl.build(:user, :admin, :with_profile_picture, attributes)
end
This will return a User that matches "[email protected]" (and print out a message saying the object already exists), or it will use the FG call to create a new object (and return a success message if the object returned is valid).
NB: You should return an unpersisted object in this block.
Example: Using FactoryGirl for a collection of objects
If you don't want to provide specific attributes, you can use the .bulk_create
function to do so. EG:
# If MyClass.count > 0, an already created message will be shown
# If MyClass.count == 0, the block will be run
# If the block fails, you'll get a red error message with the exception printed out.
SeedHelper.bulk_create(MyClass) do
FactoryGirl.create_list(:my_class, 5)
end
If you want to bulk create some associated objects for a given object, you can pass a hash of attributes to scope the .bulk_create
by:
Client.all.each do |client|
SeedHelper.bulk_create(User, {client_id: client.id}) do |client_attributes|
FactoryGirl.create_list(:user, 5, client_attributes)
end
end
You can pass a custom message through:
Client.all.each do |client|
SeedHelper.bulk_create(User, {client_id: client.id}, "Users for #{client.name}") do |client_attributes|
FactoryGirl.create_list(:user, 5, client_attributes)
end
end
# Users for DeathCorp already exists
# Created Users for DeathCorp
# Failed to create Users for DeathCorp
Example: Output
SeedHelper provides multiple methods for showing output that can be used outside of the create_resource
method:
message
A general purpose message, generally used as a header. White by default.success
Indicates a seed function was successful. Green by default.error
Indicates a seed function has failed. Red by default.resource_already_exists
Indicates that the data already exists in the database.special_message
Show a purple multiline message. I use this to show logins for seed users.
Example: Creating a rake task
SeedHelper gives you an easy way to create consistently named rake tasks. Usage is as follows:
# rake db:seed:task_name
# :environment is automatically added as a dependency
SeedHelper.create_seed_task(:task_name)
# rake db:seed:second_task_name
# Dependent on :task_name, rake db:seed:task_name will be run before :second_task_name
SeedHelper.create_seed_task(:second_task_name, [:task_name])
# rake db:seed:third_task_name
# No dependencies (other than environment) but with a custom title. This will show up as
# description of task in `rake -T` and will be printed to screen when task runs
SeedHelper.create_seed_task(:third_task_name, [], "My sick name")