How to get url of Active Storage image
Asked Answered
P

8

37

I want to get list of records with attached images as a links or files by api.

I have a simple model:

class Category < ApplicationRecord
  has_one_attached :image
  validates :name, presence: true, uniqueness: true
end

And next action:

  def index
    @categories = Category.all.with_attached_image

    render json: @categories.to_json(include: { image_attachment: { include: :blob } })
  end

That's the only way I can get image object.

And I see next results:

{"id":4,"name":"Cat1","description":""},
{"id":1,"name":"Cat2","description":"","image_attachment":
  {"id":8,"name":"image","record_type":"Category","record_id":1,"blob_id":8,"created_at":"2018-06-09T13:45:40.512Z","blob":
  {"id":8,"key":"3upLhH4vGxZEhhf3TaAjDiCW","filename":"Screen Shot 2018-06-09 at 20.43.24.png","content_type":"image/png","metadata":
  {"identified":true,"width":424,"height":361,"analyzed":true},"byte_size":337347,"checksum":"Y58zbYUVOlZRadx81wxOJA==","created_at":"2018-06-09T13:45:40.482Z"}}},
...

I can see filename here. But files lives in different folders and it doesn't seems for me like a convenient way to get and link to the file.

I couldn't find any information about this.

Updated

Accordin to iGian solution my code become:

  def index
    @categories = Category.all.with_attached_image

    render json: @categories.map { |category|
      category.as_json.merge({ image: url_for(category.image) })
    }
  end
Pena answered 9/6, 2018 at 15:11 Comment(3)
I have a model User with avatar as attachment and I can get the url in my views with <%= image_tag url_for(user.avatar) %>, maybe you can use just url_for(user.avatar).Virgo
Yes, that works, thank you!Pena
Good, glad to help!Virgo
V
52

For my User which has_one_attached :avatar I can get the url in my views with <%= image_tag url_for(user.avatar) %>. So, in controller I would use just url_for(user.avatar)

For Category which has_one_attached :image:

url_for(category.image)
Virgo answered 9/6, 2018 at 22:43 Comment(4)
how can we get Image complete data from Image_url vice-versaBellbottoms
If you need the full path you can use polymorphic_url(category.image), which includes https://... not just the path.Labbe
Try main_app.url_for(category.image)Edd
I just want to add that if you're not accessing this from a view, you can do this: Rails.application.routes.url_helpers.url_for(category.image)Judaize
G
18

Also try @object.image.service_url. This will give you the url where the image is saved. I.E. url to amazon s3 storage.

Garald answered 14/3, 2020 at 19:45 Comment(3)
This works with Rails 6.1 below, but stopped working on Rails 7. It is now renamed from service_url to just url.Frisco
This works as of Jun 2022 +1Difficulty
use url with Rails 7. Tested it on Oct 2023Foxed
I
4

Please follow this for fetching images( in case if you are using has_many_attached)

Model.images.map{|img| ({ image: url_for(img) })}
Ishmaelite answered 7/8, 2018 at 11:25 Comment(2)
I'm afraid I can't convert from single to multiple attachments using only the the line in your answer. I get either just the 'images' array in the response, or an error, meaning I'm doing something wrong. Could you possibly put this answer into the context of the original poster's 'index' method block?Of
I got this to work, would it be the correct way, syntactically? render json: @works.map { |work| work.as_json.merge({ images: work.images.map{|img| ({ image: url_for(img) })} }) } Of
D
4

This works for me with multiple images

class PostSerializer < ActiveModel::Serializer
  include Rails.application.routes.url_helpers

  attributes :id, :content , :images

  def images
    images = object.images.map do |image|
      rails_blob_path(image , only_path: true) if object.images.attached?
    end
  end
end
Densimeter answered 7/8, 2020 at 15:48 Comment(0)
G
2

I got it to work with rails_blob_url(@object.image). Notice I am calling _url not _path with the helper.

Garald answered 11/3, 2020 at 22:50 Comment(0)
B
2

If you want get this url in front end, try this :

<%= url_for(category.image) %>

and for displaying image :

<%= image_tag url_for(category.image) %>
Burdock answered 25/11, 2020 at 11:22 Comment(0)
D
1

Here is how I use active storage with AWS S3 bucket and attach image urls with domain to JSON response:

activerecord


class Imageable < ApplicationRecord
  has_many_attached :images

  def image_urls
    images.map(&:service_url)
  end

  def attributes
    super.merge({
                  image_urls: image_urls
                })
  end
end

application_controller.rb

class ApplicationController < ActionController::Base
  before_action :set_active_storage_current_host
  
  def set_active_storage_current_host
    ActiveStorage::Current.host = request.base_url
  end
end

imageables_controller.rb

class ImageablesController < ApplicationController
  include ImageablesHelper
  def update
    imageable = find_or_create
    imageable.update imageables_params
    imageable.images.purge
    imageable.images.attach imageable_params[:images]
    imageable.save!
    render json: imageable
  end
end

imageables_helper.rb

module ImageablesHelper
  def imageables_params
    params.require(:imageable).permit(:other_attributes, images: [])
  end
end
Dryly answered 23/4, 2021 at 16:37 Comment(0)
T
0

We can just use

<%= image_tag url_for(user.avatar) %>

to display any image from Turbo Stream.

For example, showing real-time post notifications with Turbo Stream, we can use following code for post partial

<!-- app/views/notifications/_post.html.erb -->
<div class="flex items-start space-x-4 bg-white p-4 rounded-lg shadow-md">
  <% if notification.item.user.avatar.attached? %>
    <%= image_tag url_for(notification.item.user.avatar), class: 'w-10 h-10 rounded-full' %>
  <% end %>
  <div class="flex-grow">
    <p class="text-gray-700">
      <span class="font-semibold text-gray-900"><%= notification.item.user.username %></span>
      added a new post:
    </p>
    <p class="mt-1 text-gray-600">
      <%= link_to notification.item.content.truncate(100), notification.item, class: "underline text-blue-600 hover:text-blue-800 font-medium" %>
    </p>
    <p class="text-sm text-gray-400 mt-1">
      <%= time_ago_in_words(notification.item.created_at) %> ago
    </p>
  </div>
  <% if notification.item.image.attached? %>
    <div class="flex-shrink-0">
      <%= image_tag url_for(notification.item.image), class: 'w-20 h-20 object-cover rounded-lg' %>
    </div>
  <% end %>
</div>
Texas answered 4/7 at 12:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.