ruby-on-railsrails-activestorageactiontextmobility

Rails Internationalisation for ActiveStorage & ActionText


Rails has internal patterns for which it generates tables to handle polymorphic associations

has_one_attached  :document
has_many_attached :pictures
has_rich_text     :body

However, this polymorphism is hard to wrangle with the polymorphism that the mobility gem provides, where one would declare:

  translates :caption, type: :string
  translates :description, type: :text

Firstly, there is an unexpected behaviour in migrations: migrating backwards before migration set-up for ActiveStorage, the tables were found to not be deleted. Migrating + restarting the server = objects were still being rendered. Only purges delete them.
I cannot fathom where I went wrong, not having modified the migration. I do notice however, for a Rails 7 application, that the class is declared as
class CreateActiveStorageTables < ActiveRecord::Migration[5.2] maybe it works on up but not down...

The following does create columns that render, can be queried and updated via the console.

class UpdateActiveStorageTables < ActiveRecord::Migration[7.0]
  def change
    add_column :active_storage_blobs, :caption, :string
    add_column :active_storage_blobs, :description, :text
  end
end

The controller action can update the blob

  def add_image
    images = params[:individual][:image]
    if images
      images.each do |image|
        @individual.images.attach(image)
      end
    end
    @individual.save
    new_image = @individual.images.last  # in the hope of no near-simultaneous addition of an image to said user
    new_image.blob.update(caption: params[:individual][:caption], description: params[:individual][:description])
  end

yes this is somewhat odd, but with the form, the added attributes (caption and description) are not part of the image data array

Can one declare this at a model level for Mobility and integrate Mobility into this action (and how, if so)?

An alternative would be to create a new class, polymorphic assuming multiple classes use ActiveStorage, to create attributes that belong to the attachment, translate those as subsequent data inputs to the attachment creation.
But how would on define the migration and model (belongs_to ActiveStorage::Attachment ?) to create such classes?


Solution

  • On my opinion has_one_attached is always more preferable over has_many_attached because you can add to "parent" model any needed columns, sort by them, etc.

    class Picture < ApplicationRecord
      extend Mobility
    
      belongs_to :imageable, polymorphic: true
    
      has_one_attached  :file
    
      translates :caption, type: :string
      translates :description, type: :text
    end
    
    class User < ApplicationRecord
      has_many :pictures, as: :imageable
    end
    

    In this case you can use these caption or description for Picture model, not for blobs