Search code examples
ruby-on-railsrubyreactjsrails-activestorage

Rails Active Storage: Get relative disk service path for attachment


I'm switching to Rails Active Storage to handle upload and storage of images locally (using the disk service) for a product catalog, and I'm having trouble getting a usable url to the image to feed into an <img> tag. I'm using React on the frontend, so I can't (easily) use Rails helpers to generate the tag.

ActiveStorage puts the files in /public/images. I can hardcode relative links to the files (i.e. http://localhost:3000/images/Ab/CD/AbCDEfGhIjkL) and it works fine.

Relevant snippet from Product.rb:

    class Product < ApplicationRecord
        attr_accessor :image_url
        has_one_attached :image

        def as_json(options)
            h = super(options)
            if self.image.attached?
                h[:image_url] = ActiveStorage::Blob.service.service_url(self.image.key)
            end
            h
        end
    end

as_json produces a JSON object to feed to React that has an entry image_url that is used for the <img>'s src attribute. With the code above, image_url contains the full path to the file (i.e. http://localhost:3000/srv/www/rails_app/public/images/Ab/CD/AbCDEfGhIjkL). Using url_for in the view produces the same result. I want it to only contain the path relative to rails root.

I could manipulate the string to remove everything before the relative path, but I foresee this causing bugs in the future if anything ever changes, so I'd much rather find a way to get ActiveStorage to just generate an appropriate string for me.

Thanks!


Solution

  • You need to use the routes helper to build of a URL to your Rails app.

    https://guides.rubyonrails.org/active_storage_overview.html#linking-to-files

    class Product < ApplicationRecord
        attr_accessor :image_url
        has_one_attached :image
    
        def as_json(options)
            h = super(options)
            if self.image.attached?
                h[:image_url] = Rails.application.routes.url_helpers.rails_blob_path(self.image)
            end
            h
        end
    end