As you know, Active Storage is the newest addition to Rails core. It provides a nice built-in solution for file uploading, and my impressions are very positive so far. It has a nice set of features including image variants, direct uploads, support for major cloud providers, and more. All these make it surprisingly competitive with the existing file upload gems.

But there’s one feature which is conspicuously missing… attachment validation. There’s no way to enforce that an attachment is present when you save a model!

Model validation, of course, is one of the fundamental features of Rails. It’s also one of the things that made me fall in love with Rails in the early days. That’s why it’s surprising that Active Storage was released without it, especially since it’s a feature of the other file upload gems. It’s become one of the top feature requests on the Rails repository, and many feel it’s a major feature lapse.

That said, it’s pretty easy to add a custom validator to gain this missing functionality. Below I’ll share the code that I use to validate my Active Storage attachments. I’ll also include a handy RSpec matcher you can use in your unit tests.

Validate that a file is attached

This validation is straight-forward. It ensures that an attached file is present when a model is saved. It’s like a presence validation but for your attachment.

Here’s some sample usage

class Person < ApplicationModel
   has_one_attached :file

   validates :file, attached: true

You’ll find the code for the validator here

Write readable unit tests with this RSpec matcher

I usually use shoulda-matchers in my unit tests. It provides a quick way to test that validations have been added to your models. Below is an RSpec matcher that will work with our brand new attachment validator.

Here’s some sample usage

describe Person do
   it { validate_attachment_of(:file) }

You’ll find the code for the matcher here

Other validators coming soon

Another common validation for uploaded files is on the content-type. You’ll usually want to restrict the file types that you allow the user to upload. For example, images should only be PNG, GIF, or JPEG. Another example is that documents should only be PDF or TXT.

Active Storage does not have a built-in content-type validation, but we can build one ourselves.