0

Since a few days, I start to pull out my hair with a problem of displaying images stored on AWS S3. The images are sent to the S3 during creation, but it is not possible to display them in the HTML. I think I missed something in the configurations.

A little background: I have a Rails 7 application with a text editor (ActionText). Since ActionText has a direct-upload approach, I have configured the app to match that: here is how I did it in

 // direct_uploads.js

addEventListener("direct-upload:initialize", event => {
  const { target, detail } = event
  const { id, file } = detail
  target.insertAdjacentHTML("beforebegin", `
    <div id="direct-upload-${id}" class="direct-upload direct-upload--pending">
      <div id="direct-upload-progress-${id}" class="direct-upload__progress" style="width: 0%"></div>
      <span class="direct-upload__filename"></span>
    </div>
  `)
  target.previousElementSibling.querySelector(`.direct-upload__filename`).textContent = file.name
})

addEventListener("direct-upload:start", event => {
  const { id } = event.detail
  const element = document.getElementById(`direct-upload-${id}`)
  element.classList.remove("direct-upload--pending")
})

addEventListener("direct-upload:progress", event => {
  const { id, progress } = event.detail
  const progressElement = document.getElementById(`direct-upload-progress-${id}`)
  progressElement.style.width = `${progress}%`
})

addEventListener("direct-upload:error", event => {
  event.preventDefault()
  const { id, error } = event.detail
  const element = document.getElementById(`direct-upload-${id}`)
  element.classList.add("direct-upload--error")
  element.setAttribute("title", error)
})

addEventListener("direct-upload:end", event => {
  const { id } = event.detail
  const element = document.getElementById(`direct-upload-${id}`)
  element.classList.add("direct-upload--complete")
})

AWS configuration

**Bucket policy**
 {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "Statement1",
                "Effect": "Allow",
                "Principal": "*",
                "Action": [
                    "s3:DeleteObject",
                    "s3:GetObject",
                    "s3:ListBucket",
                    "s3:PutObject",
                    "s3:PutObjectAcl"
                ],
                "Resource": [
                    "arn:aws:s3:::bucket-prod.lnclass.com",
                    "arn:aws:s3:::bucket-prod.lnclass.com/*"
                ]
            }
        ]
    }

configuration of the bucket now let go for Cross-origin resource sharing (CORS) I think, since actionText uses direct-upload, it is necessary to configure CORS

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "HEAD",
            "GET",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "ETag"
        ]
    }
]

with this configuration the images are sent in the compartment, but not possible to load them on the site. and I do not know where I made the mistake

Edit: ActionText loads images stored on S3 from the .

view/active_storage/blobs/blob.html.erb

 <figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>">
  <% if blob.representable? %>
    <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
  <% end %>

  <figcaption class="attachment__caption">
    <% if caption = blob.try(:caption) %>
      <%= caption %>
    <% else %>
      <span class="attachment__name"><%= blob.filename %></span>
      <span class="attachment__size"><%= number_to_human_size blob.byte_size %></span>
    <% end %>
  </figcaption>
</figure>

1 Answers1

0

Many thanks to [Rice][1] for his answer.

I detail a little, As actionText loads the images of S3 from the browser, it is necessary to be able to configure the url to load the images, then, here is how I made:

attachment--">
<% if blob.representable? %>
    <% if Rails.env == 'production' %>
       <img class: "actiontext-image" src="https://<%= Rails.application.credentials.dig(:aws, :s3_bucket) %>.s3-<%= Rails.application.credentials.dig(:aws, :s3_region) %>.amazonaws.com/<%= blob.key %>" />
            <% else %>
              <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]), class: "actiontext-image" %>
            <% end %>
          <% end %>
        
          <figcaption class="attachment__caption">
            <% if caption = blob.try(:caption) %>
              <%= caption %>
            <% else %>
              <span class="attachment__name"><%= blob.filename %></span>
              <span class="attachment__size"><%= number_to_human_size blob.byte_size %></span>
            <% end %>
          </figcaption>
        </figure>

for more security, I added the elements in an environment variable and used them in the view

region: <%= Rails.application.credentials.dig(:aws, :s3_region) %>
bucket: <%= Rails.application.credentials.dig(:aws, :s3_bucket) %>

note: so define the variables in the credentials. it's just the name of the region and the bucket

config/storage.yml
amazon:
  service: S3
  access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
  secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
  region: <%= Rails.application.credentials.dig(:aws, :s3_region) %>
  bucket: <%= Rails.application.credentials.dig(:aws, :s3_bucket) %>