Jonathan Bennett

Rails Tip: Skip has_many_attached and make a model

ActiveStorage is great, and I love the ease and flexibility of has_one_atached.

Here’s the thing though: I try to avoid has_many_attached as much as possible. Why? There are two big reasons

Unexpected Behaviour

One thing that can be unexpected when you first work with ActiveStorage’s has_many_attached is that an individual upload will replace the entire list of attachments. This makes sense when you think about it and is clearly documented so I do not fault them. It is simply something to be aware of.

And I have forgotten an uncomfortable number of times 😞

Extending Functionality

With has_one_attached, it’s pretty common to just have an image. You might have an extra field for something like a caption, but that can live on the parent model pretty naturally.

has_many_attached is different. Sticking with the same example, the images might have a caption each. You also probably want to store a position so you can reorder things etc. You could modify the ActiveStorage::Attachment model to have those fields, but that muddies the water.

No, what I recommend is a new model, say FileAttachment that has all your extra fields, and it has a has_one_attached:

class FileAttachment < ApplicationRecord
	has_one_attached :file
	
	acts_as_list # sorting images based on a position field
	
	# etc
end

class Post < ApplicationRecord
	has_many :file_attachments
end

This gives you all the power of ActiveStorage, and all the flexibility of something custom


P.S. 🎂 It’s my birthday today 🎉. Like any good hobbit, I’m giving you a gift. Fill out this form to enter a draw for a free 1-hour consult. I’ll pick a winner next Wednesday (May 14th).