Archiving Rails Database Migrations by Year
We are approaching 400 Rails database migrations in Content Harmony and they are getting a little unwieldy in my editor sidebar.
Simon Chiu has a nice rake task he posted that helps archive old database migration, and his post explains some of the reasons for doing so aside from being annoyed by scrolling.

His version pushes all files into a single archive, and I wanted a variation I could run that would organize these by year. I also didn't want to archive migrations from the current year, nor did I want this rake task to ever get run in production just in case, so here is a slight update on his rake task that takes those requirements into account:
namespace :db do
namespace :migrate do
desc "Archive migration files from past years into yearly subdirectories"
task :archive do
if Rails.env.production?
puts "ERROR: This task should not be run in production environment."
return
end
current_year = Date.current.year
migrations_path = Rails.root.join("db/migrate")
archives_path = Rails.root.join("db/migrate/archives")
puts "Archiving migration files (excluding #{current_year})..."
# Create archives directory if it doesn't exist
FileUtils.mkdir_p(archives_path)
# Get all migration files
migration_files = Dir.glob(File.join(migrations_path, "*.rb"))
archived_count = 0
migration_files.each do |file|
filename = File.basename(file)
# Extract timestamp from filename (first 14 characters: YYYYMMDDHHMMSS)
timestamp = filename[0, 14]
# Skip if timestamp is invalid
next unless timestamp.match?(/^\d{14}$/)
# Extract year from timestamp
file_year = timestamp[0, 4].to_i
# Skip files from current year
next if file_year >= current_year
# Create year-specific archive directory
year_archive_path = File.join(archives_path, file_year.to_s)
FileUtils.mkdir_p(year_archive_path)
# Move the file
destination = File.join(year_archive_path, filename)
FileUtils.mv(file, destination)
puts "Archived #{filename} to archives/#{file_year}/"
archived_count += 1
end
if archived_count > 0
puts "Successfully archived #{archived_count} migration file(s)."
puts "Current migration files remain in db/migrate/"
else
puts "No migration files to archive (all files are from #{current_year} or later)."
end
end
end
end
Here is what you'll see in console upon running this:

And here is what you'll see if you run this twice in the same year:

If you're running Standard or Rubocop you'll likely need to make a change like this as well to ignore older migrations that don't pass linting:
ignore:
# ignore old database migrations
- "db/migrate/archives/**/*"

"Can't you just drag and drop these files manually?"
Yeah absolutely. But this way is more fun.
Comments