We have a client’s site that we are currently updating from Ruby 2.5.0 / Rails 5.0.1 using the Paperclip gem version 5.0. We looked at a number of ways to make the migration to a current state: Ruby 3.0.1p64 / Rails 6.1.4.1 and using active storage and spend over a full day fumbling through tutorials and various directions offered on different sites… nothing worked right. It seems the problem is that 1) most of the examples and tutorials are for very specific configurations that don’t easily extrapolate to what we needed, and 2) the rest were outdated or dependent upon using deprecated version of gems that are no longer available.
The next day we decided to create our own solution and it worked flawlessly. We’re going to share that here.
Our Approach
We stepped back and took a look at what we were trying to accomplish:
- Update the site to current version of Ruby and Rails
- Convert all images and image functionality from Paperclip to Active Storage
- Do not lose any data
Our Path to Success
We moved forward with a clean install of Rails 6.1.4.1 using Ruby, 3.0.1p64. We then installed, initialized and configured the following (for our specific needs):
- Active Storage
- Bootstrap 5
- Devise
- MySQL2 gem and configured it to use a copy of the current active DB
Next we copied the user model over to the new site install and removed any references to Paperclip and added the references for activestorage. see: fig. 1 and 2
We then located the directory where Paperclip was storing all the existing images. Usually Paperclip stores them in the public folder under a path that looks like this (unless you changed the defaults):
"/public/system/:class/:attachment/:id_partition/:style/:filename"
We copied the entire “system” directory into the “public” folder of the updated site’s newly installed instance.
In our case our “:class” was the user model, “:attachment” was “image”, “:id_partition” was “000/000/user id”. We used “original” for the style because paperclip always keeps an original so our real path looks like this:
"/public/system/users/image/000/000/:user_id/original/"
We know that paperclip stores the attachment filename in the database table for the model in a column named: (:attachment)_file_name. So in our case: image_file_name.
Next we created a rake task that did the following and ran it:
- Retrieved all users from the database
- Foreach user, grabbed the user_id and filename from the record
- Built the real path to the file using the known data and the data from step 2
- Tested the file path to verify it exists and ignored and skipped if it didn’t
- Opened and programmatically attached the file to the user record using activestorage
See below:
Final Steps
We verified that 1) activestorage did indeed attach and copy all the files to it’s own storage path on the server and 2) that those attachments could be loaded in views using activestorage methods.
Since the migration was successful we removed the entire “system” directory from the “public” directory so as to avoid a set of duplicate and never to be used assets.
Note:
We actually had multiple attachment images for each user: (image, before1, after1, before2, after2, before3, after3, before 4, after4, before5, after5, before6, after6). In the example above we just repeated steps 2-5 for each user and in our rake task so we could convert all of their images as seen above in our rake task code.
Conclusion
3,450 images totaling 5.9GB successfully transferred into activestorage!
Sometimes looking for a readily canned solution is not the easiest or shortest path. In the future we will be looking at what our own solutions entail before looking for outside information / code / fixes.
If you wound up here because of the same issues we were facing, we hope this helps you get well on your way to a successful migration.