Ask A Question

Notifications

You’re not receiving notifications from this thread.

How would one go about sorting ActiveStorage has_many_attached objects?

Aaron Belsham asked in Rails
Hey there,

Just wondering if anyone can shed some light here as the Google search is pretty thin right now for ActiveStorage.

Is there a way to a a property (say sort_order) to each of the has_many_attached objects and then later be able to re-sort those without having to wrap the ActiveStorage items beneath a has_many associated model, e.g Image which itself has_attached a single attachment.

A working example is a classified advertisement that has many images, currently we have a has_many association to Image, but wanting to simply the creation process to take advantage of a multi-select option on the form upload.

Cheers

Aaron
Reply
Hey Aaron,

At a high level:

You'd need something to sort by. You could modify the ActiveStorage models and add a column to sort by.

Or you could just keep an array of the attachment IDs for those on your model.

Either way would work, but I would probably prefer the second option. Once you have the attribute to sort by, you just grab the attachments order by the sort order that's saved.
Reply
Hey Chris,

Thanks for the answer, yes, at a high level that seems like a reasonable way to go about it, I think the flexibility of calling model.images scoped by the relevant order probably beats that at this time though so probably not worth the pain to migrate completely just for a simple bit of form magic!

I had always imagined ActiveStorage would end up with some kind of generator similar to ActiveRecord to allow this kind of extra rails goodness to be applied like adding your own properties to the attachments, scope the has_many_attacheds and so on.

Cheers

Aaron


Reply
Since the models are shared with ALL uploads, if you extend say ActiveStorage::Attachment, all attachments will have that functionality even though they might not need it.

ActiveStorage is quite a different approach than the other file uploading tools like Shrine. Plus it's fairly early right now and some of the functionality only works well with images (namely the variants stuff) which gets annoying if you want to do things like extend AS to make for transcoding video easier or whatever.
Reply

Hi, @chris I am having this problem now trying to decide if to use ActiveStorage. If I go with your second option (I will have attachments in various places, and I think I will need sorting only in one case), what's the easiest/most efficient way of sorting the images by the given array of ids? Thanks!

Reply

In case others need this, I found this gem, it can sort by array of ids with a native SQL query and return a relation.

https://github.com/khiav223577/find_with_order

Reply

Add an Array/JSON Array type column to the model which declares the has_many_attached and store ids of ActiveStorage::Attachments in it. Then you can do :

# app/models/entry.rb
class Entry < ApplicationRecord
  has_many_attached :pictures


  def ordered_pictures
    pictures.sort_by{ |pic| ordered_picture_ids.index(pic.id) || (pic.id*100) }
  end

  def ordered_picture_ids=(ids)
    super(ids.map(&:to_i)) # convert any ids passed to this method to integer
                           # this is just for security reasons,
                           # you don't need to do this for the feature to work
  end
end

more detailed example at: blog.eq8.eu/article/order-attachments-in-rails-activestorage-has_many_attached.html

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 86,946+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.