Migrating Cloudinary Accounts

A handy Ruby script if you ever have to migrate buckets for Cloudinary.

Learned this snippet from @cloudinary

Migrating Cloudinary Accounts

The other month we shipped a new product at Bento that enabled users to show pop-ups to their customers to collect email addresses. Awesome, right?

I was so excited to ship it that I accidently shipped it with the wrong Cloudinary account hooked up ... and because that was a development acccount it started to hit limits on the free plan so stopped serving content on those pop-ups. OOPS! 🤦‍♂️

Running multiple Cloudinary paid accounts is a tad silly so I reached out to support to ask them if they could help. The following is a Ruby script they sent to me that helped me migrate all my content from one account to another all in Ruby.

Hope this helps someone else who is in a pickle!

# Call the Upload API for a file containing filenames or URLs, in parallel
# Applies various upload options

gem 'cloudinary';
require('cloudinary')
require 'csv'

# Account Credentials for destination account
Cloudinary::config_from_url("<CLOUDINARY_URL>")

Cloudinary.config.cloud_name
files_to_upload = []

# Optional: Get the file list from CSV file.
CSV.foreach("test.csv") {
	|row| files_to_upload << row[0] # first column has the URLs
}
puts "Uploading to cloud-name: " + Cloudinary::config.cloud_name
puts files_to_upload.size.to_s + " resources total";
puts files_to_upload if files_to_upload.size < 100 
puts "Start time: "+ Time.new.inspect
sleep 10; # Leave the output above on the screen for a while before proceeding further

# Process uploads in parallel 
transferred_resources = []
threads = []
number_of_threads = 5

chunk_size = files_to_upload.size/number_of_threads
chunks = files_to_upload.each_slice(chunk_size).to_a;0
chunks.each do |res|
    threads << Thread.new {    	
    	res.each_with_index do |resource,i|
			begin

				# Decide how to name the new file - in this example, last part of the URL, excluding extension
				new_public_id = resource.split("/")[-1].sub(/\.[^.]+\z/, '') 

				puts new_public_id

				puts "#{i}/#{res.length} #{resource} - "+ Time.new.inspect

				result = Cloudinary::Uploader.upload(
					resource,
					:public_id => new_public_id,
					:folder => '',
					:type => 'upload', 
					:overwrite => false,
					:tags => ["migrated"], 
					return_error: true);0
				
				puts "#{i}/#{res.length} #{resource} - " + Time.new.inspect
				transferred_resources.push(result);0
			rescue Exception => e
				puts e;
				sleep(10); # wait before continuing
			end 
		end
		}
	end;0
threads.each { |thr| thr.join }

# Displays any error messages
transferred_resources.select{|a| a['error']}
puts "End time: "+ Time.new.inspect

Then, after you've completed the upload, go into your database and gsub the cloud_name and you're done!

Subscribe to my personal updates

Get emails from me about building software, marketing, and things I've learned building products on the web. Occasionally, a quiet announcement or two.

Email marketing powered by Bento