web-dev-qa-db-fra.com

Comment récupérer l'URL d'une pièce jointe avec Rails Active Storage avec S3

Rails version 5.2

J'ai un scénario dont j'ai besoin pour accéder à l'url publique de Rails Active Storage avec Amazon s3 pour créer un fichier Zip avec un travail d'arrière-plan Sidekiq.

J'ai du mal à obtenir l'URL du fichier réel. J'ai essayé de suivre

Rails_blob_url

mais ça me donne la suite

http://localhost:3000/Rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBZUk9IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--9598613be650942d1ee4382a44dad679a80d2d3b/sample.pdf

Comment accéder à l'URL du fichier réel via sidekiq?

storage.yml

 test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

development:
  service: S3
  access_key_id: 'xxxxx'
  secret_access_key: 'xxxxx'
  region: 'xxxxx'
  bucket: 'xxxxx'

development.rb

  config.active_storage.service = :development

Je peux y accéder très bien sur l'interface web mais pas dans le sidekiq

11
Shani

Utilisez ActiveStorage::Blob#service_url . Par exemple, en supposant un modèle Post avec un seul header_image Attaché:

@post.header_image.service_url
34
George Claghorn

Mon cas d'utilisation consistait à télécharger des images vers S3, qui auraient un accès public à TOUTES les images du compartiment afin qu'un travail puisse les récupérer plus tard, quelle que soit l'origine de la demande ou l'expiration de l'URL. Voilà comment je l'ai fait. (Rails 5.2.2)

Tout d'abord, la valeur par défaut pour le nouveau S3 bucked est de garder tout privé, afin de vaincre qu'il y a 2 étapes.

  1. Ajoutez une stratégie de compartiment générique. Dans AWS S3 >> votre compartiment >> Autorisations >> Stratégie de compartiment
{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "AllowPublicRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your-bucket-name/*"
        }
    ]
}
  1. Dans votre compartiment >> Autorisations >> Paramètres d'accès public, assurez-vous que Block public and cross-account access if bucket has public policies Est défini sur false

Maintenant, vous pouvez accéder à tout dans votre compartiment S3 avec juste le blob.key Dans l'url. Plus besoin de jetons avec expiration.

Deuxièmement, pour générer cette URL, vous pouvez soit utiliser la solution de @Christian_Butzke: @post.header_image.service.send(:object_for, @post.header_image.key).public_url

Cependant, sachez que object_for est une méthode privée sur service, et si elle est appelée avec public_send, vous obtiendrez une erreur. Ainsi, une autre alternative consiste à utiliser le service_url per @George_Claghorn et à supprimer simplement tous les paramètres avec un url&.split("?")&.first. Comme indiqué, cela peut échouer dans localhost avec une erreur manquante d'hôte.

Voici ma solution ou un "logo" téléchargeable stocké sur S3 et rendu public par défaut:

#/models/company.rb
has_one_attached :logo
def public_logo_url
    if self.logo&.attachment
        if Rails.env.development?
            self.logo_url = Rails.application.routes.url_helpers.Rails_blob_url(self.logo, only_path: true)
        else
            self.logo_url = self.logo&.service_url&.split("?")&.first
        end
    end
    #set a default lazily
    self.logo_url ||= ActionController::Base.helpers.asset_path("default_company_icon.png")
end

Profitez de ^ _ ^

4
genkilabs

Si vous avez besoin de tous vos fichiers publics, vous devez rendre publics vos téléchargements:

Dans le fichier config/storage.yml

Amazon:
  service: S3
  access_key_id: zzz
  secret_access_key: zzz
  region: zzz
  bucket: zzz
  upload:
    acl: "public-read"

Dans le code

attachment = ActiveStorage::Attachment.find(90)
attachment.blob.service_url # returns large URI
attachment.blob.service_url.sub(/\?.*/, '') # remove query params

Il renverra quelque chose comme: " https://foo.s3.amazonaws.com/bar/buz/2yoQMbt4NvY3gXb5x1YcHpRa "

Il est lisible par le public en raison de la configuration ci-dessus.

1
Aivils Štoss

Un peu en retard, mais vous pouvez également obtenir l'URL publique comme ceci (en supposant un modèle Post avec une seule image header_image jointe comme dans l'exemple ci-dessus):

@post.header_image.service.send(:object_for, @post.header_image.key).public_url
0
Christian Butzke