Recently we’ve been making a more conscious effort to improve the quality of our seed data.
Firstly, to make it easier to onboard new team members. Secondly, to make the app ready for Review Apps. Certainly, it’s a great thing to be able to just re-seed your database if your local experiments go awry 😅
The kind of seeds I’ve seen over the years typically neglect images. They either use a minimal placeholder, use a few nicer images that are repeated over and over and checked into source control, or don’t do anything at all. How can we get this kind of awesomeness with almost no effort?
Enter…
Unsplash
Unsplash is the internet’s source of freely useable images. It comes with a simple API we can use to seed our images from. Here’s how:
Sign up and create your app to get your API credentials.
Install the gem:
# API for seeding free, high-definition photos
gem 'unsplash'
Initialize it (e.g. config/initializers/unsplash.rb
):
Unsplash.configure do |config|
config.application_access_key = ENV['UNSPLASH_ACCESS_KEY']
config.application_secret = ENV['UNSPLASH_SECRET_KEY']
config.utm_source = 'your_app_name'
end
With that set up, you can fetch a collection of images with a single command:
unsplash_images = Unsplash::Photo.search('architecture', 1, 25)
This tells Unsplash to return page 1 of the results and use 25 records per page.
We use Shrine which makes it easy to use a remote URL as a source of attachment. To accomplish that, add the following to your attacher:
plugin :infer_extension # Unsplash image URLs don't come with an extension
plugin :remote_url, max_size: 20.megabytes # or your custom limit
Here’s the final implementation used to seed data:
module Seeds
module Images
def self.seed(property:)
p 'Seeding property images...'
# Add more than 20 items to test pagination.
unsplash_images = Unsplash::Photo.search('architecture', 1, 25)
unsplash_images.each do |unsplash_image|
image = Properties::Image.create!(
property: property,
category: Properties::Image.categories.keys.sample,
taken_on: rand(5..200).days.ago,
title: unsplash_image.description,
file_remote_url: unsplash_image.urls.regular
)
Properties::Images::Publisher.(image)
end
p 'Done seeding images! 🎉'
rescue Unsplash::UnauthorizedError
p 'Unsplash API keys not found, no images will be seeded.'
end
end
end
Rescuing from Unsplash::UnauthorizedError
gives us the flexibility to make this an opt-in
feature available if you set up your Unsplash ENV variables.
Careful observer will notice that this is not your typical structure of seeds.rb
. In an
effort to make our seeds more maintainable, we’ve broken it down into modules.
Every module has a single responsibility for seeding just one type of records.
We keep these under db/seeds/*.rb
.
This allows for a wonderfully clean seeds.rb
file 🎉
Dir[Rails.root.join('db', 'seeds', '*.rb')].each { |f| require f }
ApplicationRecord.transaction do
property = Property.create(name: 'Empire State Building')
Seeds::Images.seed(property: property)
# Seeds::Tenants.seed(property: property)
# Seeds::Files.seed(property: property)
# etc.
end
Eager to learn about your experience with making seeds more useful!