Handling Image and Video Uploads in your Rails App Using Active Storage
Over the years, Rails has evolved and has become one of the most powerful web application frameworks available. It comes with so many built in functionalities; it makes development of modern web applications much easier and more fun. It’s almost…dare I say it… ✨ magical ✨ 😜.
In my Rails app, I wanted a user to be able to create a post and be able to upload an image or a video along with it. Kinda like, you know… in Facebook. (Don’t worry Mark Zuckerberg, I’m not ready to take your job yet. 😉)
Up to this point, using the built-in SQLite database, I’ve only been managing and storing specific and limited datatypes associated with my app — INTEGERS and TEXT. But images and videos make everything so much more fun. And my app needs to be fun! So how do I handle image and video uploads in Rails?
While digging around in the wide world of the web, I came across some interesting gems: Paperclip, CarrierWave, and Shrine. These three looked promising! (Well…except for Paperclip. It’s deprecated. Gone before I even got a change to get to know it.😔)
But then I stumbled upon Active Storage!
Active Storage is already a part of Rails! It’s a gem that works in tandem with Active Record. It makes use of already built-in Blob and Attachment models, which makes associating files with existing application models quite a breeze. And staying on brand with Rails, implementation of Active Record is quite effortless.
First let’s get set-up. While inside our Rails app directory, we’ll run the following command in our terminal:
This will create this migration:
Running said migration will make our schema look like this:
As you can see, running two commands has created two new tables for us. Though we won’t be directly interacting with these two tables, here’s a quick rundown of what they are for:
The active_storage_blobs table is where information about our uploaded file (in our case an image or a video) is stored. Information such as filename, content_type, metadata, etc.
Meanwhile, the active_storage_attachments table is a joiner table that contains references that connect a blob (binary large object) and a record (data stored about an instance of our model).
(For a cool illustration of these relationships happening under the hood, check out this article by The Pragmatic Studio.)
Now that our tables are all set, we’ll need to declare associations in our Model. (I’ve named my attribute post_file, but you can name it however you want.)
The above line of code (also know as a macro) shoulders the responsibilities and functionalities of these two lines:
Now let’s move on to our Views. We’ll need to create a form that lets our user select a file to upload from their computers. We can do that using a file_field.
With that said, in order for this to work, over in our Controller, we need to make sure that we permit our :post_file attribute when we pass our form params to our Model.
And that’s it. With these few steps we’ve handled user upload of images and videos in our Rails app!
So now, how do we get access to what we’ve stored, and display it on a page? We can utilize image_tag or video_tag.
In my app, a user can create a post with or without an image or a video. In the above code, I’ve used the method attached? (which returns a boolean) to check if there is a file associated with the post. If there is, we’re also going to check the content_type of the file (whether it’s an image or a video). Then based on our conditions, the image_tag or video_tag will help render and display our file.
There you have it. We are on our way to creating a lit Rails app!
(To apply restrictions on the file a user can upload, you can write validations. I also want to mention that during development, uploaded files are stored on the local disk. Once the app moves to production environment, Active Storage facilitates uploading files to a cloud storage service like Amazon S3, Google Cloud Storage, or Microsoft Azure Storage.)