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
Utilisez ActiveStorage::Blob#service_url
. Par exemple, en supposant un modèle Post
avec un seul header_image
Attaché:
@post.header_image.service_url
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.
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "AllowPublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}
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 ^ _ ^
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.
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