There are several ways to migrate files between ActiveStorage Provider. I'm gonna use the mirroring way.

First setup your new ActiveStorage provider into config/storage.yml. Let's say for the sake of this post we're going to migrate from local Disk based storage to S3.

Here here is my S3 definition:

amazon:
  service: S3
  access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
  secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
  bucket: agdum
  region: us-east-1

Done't forget to add your AWS credentials to Rails Credentials file.

rails credentials:edit

Now setup the mirroring provider in config/storage.yml:

mirror:
  service: Mirror
  primary: local
  mirrors: [ amazon ]

Set the local as primary and amazon as mirror.

Now change the Active Storage service to mirror in your environment file (config/environments/production.rb):

config.active_storage.service = :mirror

Now log onto rails console and start migration. If you're on Rails <= 6.0:

ActiveStorage::Blob.find_each do |blob|
  local_file = ActiveStorage::Blob.service.primary.path_for(blob.key)
  mirror = blob.service.mirrors.first
  mirror.upload(blob.key, File.open(local_file), checksum: blob.checksum) }
end

If you're on Rails > v6.0, it's even easier:

ActiveStorage::Blob.find_each(&:mirror_later)

That's all you need. Now switch ActiveStorage service to amazon in your environment file (config/environments/production.rb):

config.active_storage.service = :amazon

And you're done. All your files now automatically will be uploaded to S3 and new and existing files will be served from S3. Now have a cup of tea or peace of mind!




What's on your mind?