2

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!

TFrazee
  • 792
  • 6
  • 20

1 Answers1

4

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
Nate
  • 2,364
  • 1
  • 10
  • 16
  • Thanks! I had tried that but encountered another error. I solved it using the solution at https://stackoverflow.com/questions/7219732/missing-host-to-link-to-please-provide-host-parameter-or-set-default-url-optio/48529627#48529627, and in combination with this it is now working. – TFrazee Apr 28 '19 at 03:44
  • Nice! Oh, if the React app is hosted on the same domain as the Rails app, you could always add `only_path: true` to the `rails_blob_path` method call. Then it would make URLs that don't include a domain. eg: `/images/Ab/CD/AbCDEfGhIjkL` – Nate Apr 28 '19 at 03:45
  • @TFrazee HI would you mind explaining how it works? I tried the solution above but it just gave me a URL that is not downloadable or accessible using a browser. – Sam Kah Chiin Apr 29 '22 at 07:46
  • On the latest version of rails, I’d just use `product.image.url`. The attachment’s url method will give you an S3 url if you’re configured for S3, or a Rails blob url if it’s the disk store. – Nate May 01 '22 at 04:14