Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActiveStorage "media library" / dashboards for blobs and attachments #1560

Open
sedubois opened this issue Feb 26, 2020 · 7 comments
Open

ActiveStorage "media library" / dashboards for blobs and attachments #1560

sedubois opened this issue Feb 26, 2020 · 7 comments
Labels
documentation how to use administrate, examples and common usage resolver

Comments

@sedubois
Copy link
Contributor

sedubois commented Feb 26, 2020

What were you trying to do?

I tried to generate dashboards to visualize/manage our ActiveStorage blobs and attachments, hopefully in order to see which kind of blobs we have in the DB, which records are pointing to them, what size they have, which ones are orphan, etc.

Or is there some "official" way to get such a "media library/manager" in Rails/ActiveStorage?
How do other Rails projects answer this need? Wordpress has a "Media library" showing thumbnails of all available media and it would be great to get a basic equivalent of this. Under the hood as a storage service I am currently trialling cloudinary, which does act as such a media library where all assets can be browsed, but the correspondence between the assets visible there and the contents of the DB is not obvious. For instance, how to find where a specific image found in Cloudinary is used in our app? How to identify orphan files? Sometimes I've been seeing inexplicable ActiveStorage::IntegrityError which led me to feel like more transparency into what's happening would be useful. EDIT: I was using Cloudinary as storage service and the IntegrityError seemed to occur when I moved the images into sub-folders in the Cloudinary dashboard (to organize the assets a bit better). I didn't realize this would affect the access from ActiveStorage. Based on this comment it looks like I might have been able to re-establish the link by updating the blob's key.

Anyway, adding active_storage_blobs and active_storage_attachments to Administrate looks like a useful solution to better visualize the ActiveStorage assets, which led me to write this issue.

NB: this question concerns managing all ActiveStorage assets, not how to display/edit an indiviual resource's ActiveStorage attachment. I already managed to do that using administrate-field-active_storage.

What did you end up with (logs, or, even better, example apps are great!)?

To start, I tried to make a dashbord for ActiveStorage::Blob. As the model is namespaced, first it is necessary to fix the location of the generated controller and dashboard (see #1291 (comment)):

rails g administrate:dashboard ActiveStorage::Blob
mkdir app/controllers/admin/active_storage/ app/dashboards/active_storage/
mv app/controllers/admin/blobs_controller.rb app/controllers/admin/active_storage/
mv app/dashboards/blob_dashboard.rb app/dashboards/active_storage/

I also add the route:

# config/routes.rb
Rails.application.routes.draw do
  ...
  namespace :admin do
    ...
    namespace :active_storage do
      resources :blobs
    end
  end
  ...
end

OK, now I can view /admin, with "Active Storage Blobs" visible in the left menu:

Screenshot 2020-03-30 at 15 01 10

However if I click it, which goes /admin/active_storage/blobs, I get undefined method 'admin_blob_path' thrown by polymorphic_path([namespace, resource]) and various link_to in _collection.html.erb. I can workaround all these issues with this kind of hack:

<% show_path = if resource.is_a? ActiveStorage::Blob
                     admin_active_storage_blob_path(resource)
                   else
                     [namespace, resource]
                   end
%>
# And similar for edit and destroy routes

What versions are you running?

  • Rails 6.0.2.2
  • administrate 0.13.0 revision c28e4c6
  • cloudinary 1.13.2
  • administrate-field-active_storage 0.2.2
@sedubois sedubois added the bug breakages in functionality that is implemented label Feb 26, 2020
@sedubois sedubois changed the title How to manage all ActiveStorage blobs and attachments? ActiveStorage "media library" / dashboards for blobs and attachments Feb 26, 2020
@pablobm
Copy link
Collaborator

pablobm commented Mar 5, 2020

OK, so there are several things here.

Some of what you list is "generic" ActiveStorage stuff as mentioned at Dreamersoul/administrate-field-active_storage#30 (comment). I have done very little work with ActiveStorage (and none at all with Cloudinary) but it does sound like Administrate shouldn't be concerned with them.

Then there's generating the dashboards. The dashboard generator currently fails at namespaced models, and this is a known bug. Your approach of moving things around manually looks correct to me as a workaround.

The issue with admin_blob_path looks to me like another namespacing issue. Possibly it should be admin_active_storage_blob_path, but the namespace got lost along the way. Would you be able to find where this is happening?

@sedubois
Copy link
Contributor Author

sedubois commented Mar 5, 2020

The issue with admin_blob_path looks to me like another namespacing issue. Possibly it should be admin_active_storage_blob_path, but the namespace got lost along the way. Would you be able to find where this is happening?

I don't have time right now to dig more but there seems to be something specific going on with ActiveStorage. I use Globalize and PaperTrail for which I did manage to generate everything correctly (see here). It seems that it is only in the case of ActiveStorage that the generated path look this way.

@nickcharlton nickcharlton added dashboards how administrate presents fields and displays data feature new functionality that’s not yet implemented namespacing models with a namespace and removed bug breakages in functionality that is implemented labels Mar 26, 2020
@sedubois
Copy link
Contributor Author

sedubois commented Mar 30, 2020

OK so the main issue was that ActiveStorage's routing file contains this:

resolve("ActiveStorage::Blob") { |blob, options| route_for(:rails_blob, blob, options) }
resolve("ActiveStorage::Attachment") { |attachment, options| route_for(:rails_blob, attachment.blob, options) }

This allows to resolve polymorphic_path(blob) as blob_path, but polymorphic_path([:admin, blob]) then results in admin_blob_path which doesn't exist and we can't fix it by making another resolve clause for the admin route (see resolve documentation):

NOTE: This custom behavior only applies to simple polymorphic URLs where a single model instance is passed and not more complicated forms

NOTE: The +resolve+ method can't be used inside of a scope block such as +namespace+ or +scope+ and will raise an error if it detects that it is.

Instead this seems to work (can the repetitions admin_blob/admin_blobs/edit_admin_blob be somehow simplified?):

Rails.application.routes.draw do
  ...
  namespace :admin do
    ...
    namespace :active_storage do
      resources :blobs
      resources :attachments
    end
  end

  direct(:admin_blob) { |blob, options| route_for(:admin_active_storage_blob, blob, options) }
  direct(:admin_blobs) { |opts| route_for(:admin_active_storage_blobs, opts) }
  direct(:edit_admin_blob) { |blob, opts| route_for(:edit_admin_active_storage_blob, blob, opts) }
  direct(:admin_attachment) { |attachment, options| route_for(:admin_active_storage_attachment, attachment, options) }
  direct(:admin_attachments) { |opts| route_for(:admin_active_storage_attachments, opts) }
  direct(:edit_admin_attachment) { |attachment, opts| route_for(:edit_admin_active_storage_attachment, attachment, opts) }
end

As a reminder the controllers and dashboards can be generated as follows:

rails g administrate:dashboard ActiveStorage::Blob
rails g administrate:dashboard ActiveStorage::Attachment
mkdir app/controllers/admin/active_storage/ app/dashboards/active_storage/
mv app/controllers/admin/blobs_controller.rb app/controllers/admin/active_storage/
mv app/controllers/admin/attachments_controller.rb app/controllers/admin/active_storage/
mv app/dashboards/blob_dashboard.rb app/dashboards/active_storage/
mv app/dashboards/attachment_dashboard.rb app/dashboards/active_storage/

Then the dashboard configs and the controllers need to be tweaked:

# app/dashboards/active_storage/blob_dashboard.rb
  ATTRIBUTE_TYPES = {
    id: Field::Number,
    key: Field::String,
    # TODO figure out how to support the actual ActiveStorage::Filename type
    # (this throws an error when creating new record)
    filename: Field::String,
    content_type: Field::String,
    metadata: Field::Text,
    byte_size: Field::Number,
    checksum: Field::String,
    created_at: Field::DateTime,
    attachments: Field::HasMany.with_options(class_name: "ActiveStorage::Attachment"),
    preview_image_attachment: Field::HasOne.with_options(class_name: "ActiveStorage::Attachment"),
    preview_image_blob: Field::HasOne.with_options(class_name: "ActiveStorage::Blob"),
  }.freeze

# app/dashboards/active_storage/attachment_dashboard.rb
  ATTRIBUTE_TYPES = {
    id: Field::Number,
    name: Field::String,
    record: Field::Polymorphic.with_options(classes: [Post]),
    blob: Field::BelongsTo.with_options(class_name: "ActiveStorage::Blob"),
    blob_id: Field::Number,
    created_at: Field::DateTime,
  }.freeze

At this point we have a way to browse and edit the blob and attachment tables:

Screenshot 2020-03-30 at 17 06 01

Screenshot 2020-03-30 at 17 06 43

The next step would be to be able to actually preview the blobs and download them.

@pablobm
Copy link
Collaborator

pablobm commented Apr 10, 2020

Thank you for the research @sedubois! It looks to me that the solution here is to document this. Possibly on the Wiki. I'll tag it for documentation.

@pablobm pablobm added documentation how to use administrate, examples and common usage and removed feature new functionality that’s not yet implemented labels Apr 10, 2020
@sedubois
Copy link
Contributor Author

sedubois commented Apr 17, 2020

Rails 6.1 is adding a new ActiveStorage::VariantRecord model with accompanying *variant_record* routes, so they also need to be added. Here is a more general method (instead of 9 separate direct lines) to do so:

  namespace :admin do
    namespace :active_storage do
      resources :blobs
      resources :attachments
      resources :variant_records
    end
  end

  [:blob, :attachment, :variant_record].each do |model|
    %W[admin_#{model} admin_#{model}s edit_admin_#{model}].each do |route_name|
      direct(route_name.to_sym) do |blob, options|
        route_for(route_name.sub("admin", "admin_active_storage").to_sym, blob, options)
      end
    end
  end

@sedubois
Copy link
Contributor Author

The open-source Spina CMS has a "media picker" feature built on top of the Trix editor and Active Storage, so it looks feasible:

Screenshot 2022-03-30 at 16 27 37

Screenshot 2022-03-30 at 16 36 02

https://github.com/SpinaCMS/Spina/blob/84d46b0b6756af6a5bfa625ea2c6c5a843ea67e0/app/models/spina/image.rb#L5

module Spina
  class Image < ApplicationRecord
    # ...
    has_one_attached :file 

https://github.com/SpinaCMS/Spina/tree/fcb682a1055e691182e65ace9e206f3bd519f6e6/app/components/spina/media_picker

@sedubois
Copy link
Contributor Author

sedubois commented Jul 9, 2022

FYI, we managed to implement a basic "media gallery" in our app admin dashboard (on top of administrate) to re-attach Active Storage blobs instead of needing to re-upload files every time. We use Stimulus to listen to the Trix editor events and deliver the view through ajax using Turbo Frames.

@pablobm pablobm added resolver and removed namespacing models with a namespace dashboards how administrate presents fields and displays data labels Apr 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation how to use administrate, examples and common usage resolver
Projects
None yet
Development

No branches or pull requests

3 participants