I am creating a PDF which contains images which are stored on Amazon S3.
My Rails application uses https, so also the URL to the S3 image is https, which is configured in production.rb:
config.paperclip_defaults = {
:storage => :s3,
:s3_protocol => :https
}
The issue is that the S3 bucket has a security bucket policy that it only shows the image when it is coming from my web domain. This works well when showing the image in the view, because the referer is then my web domain which is whitelisted.
The issue when creating the PDF is that wicked_pdf tries to retrieve the image, but S3 can't see it is coming from my web domain and returns a 403 Forbidden. So what can I do to solve this?
Since you've tagged your question with wicked-pdf I assume that's what you're using. It looks like this is a known problem with some versions of that gem. The linked question gives several options to solve it.
Is your CORS configured in AWS? https://aws.amazon.com/blogs/aws/amazon-s3-cross-origin-resource-sharing/
Related
I am trying to serve apple-app-site-association from the S3 via CloudFront distribution via my custom domain.
But when I am given a path like below, It's started downloading rather than showing in the browser.
https:/mycustomdonain.com/.well-known/apple-app-site-association
Do I need to make any setting at S3 or CloudFront level to make it work?
Note: The application is developed in Angular.
Thanks
As Christos says, you need to set the content-type response header in S3, which then also applies to Cloudfront HTTPS URLs.
Here is an example of mine, that I use for deep linking and OpenID Connect with an HTTPS redirect URI:
https://mobile.authsamples.com/.well-known/apple-app-site-association
Further details on how this looks in my blog post, where you set the content type by editing tte file properties:
In my Rails app my users can upload images via carrierwave and image magic. Works great.
Now I am trying to generate a PDF with the image so in my download.pdf.erb I have
<%= wicked_pdf_image_tag('https://s3.eu-central-1.amazonaws.com/bucketname/uploads/image/image/1/thumb_71fxg4BPTuL._SY450_.jpg') %>
In my browser I can access the URL and see the image but in my PDF file on production mode I only see a grey dot. On AWS the permission for the bucket and image are all public.
On my local server the PDF loads with the image.
Any ideas?
I solved and, although it's a workaround at might compromise the security of the app, here is what I did:
My app serves via HTTPS but still, removing the HTTPS from the S3 files solved the problem.
image_url.gsub('https','http')
This is about a Rails app on Heroku that runs behind CloudFront and serves ActiveStorage images from the Bucketeer add-on.
Cache config in both the Rails app itself and CloudFront are right on target for css, js, and even key, important requests (like search results, 3rd party info fetched from APIs, etc).
What I can't figure out how to cache are the images that come from the Bucketeer add-on.
Right now the images seem to come from the Bucketeer bucket every time. They show up with no Cache TTL.
I'd like for them to be cached for up to a year both at the CloudFront level and the visitor's browser level.
Is this possible?
It seems like the Bucketeer add-on itself gives us no control over how the bucket and/or the service handles caching.
Where can I force these files to show up with caching instructions?
Thanks for sharing your findings here
Additionally, I found that S3Service accepts upload options
https://github.com/rails/rails/blob/6-0-stable/activestorage/lib/active_storage/service/s3_service.rb#L12
So you can add the following code to your storage.yml
s3:
service: S3
access_key_id: ID
secret_access_key: KEY
region: REGION
bucket: BUCKET
upload:
cache_control: 'public, max-age=31536000'
For a full list of available options refer to AWS SDK
After a lot of searching, I learned that Bucketeer does give bucket control. You just have to use AWS CLI.
Here is the link to AWS docs on CLI:
https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html
And here is the link where Bucketeer tells you how to get started with that on their service:
https://devcenter.heroku.com/articles/bucketeer#using-with-the-aws-cli
This means you can install AWS CLI, do the aws configure with the credentials Bucketeer provides, and then go on to change cache-control in the bucket directly.
AWS does not seem to have a feature for setting cache-control defaults for an entire bucket or folder, so you actually do it to each object.
In my case, all of my files/objects in the bucket are images that I display on the website and need to cache, so it's safe to run a command that does it all at once.
Such a command can be found in this answer:
How to set expires headers to all images in a bucket in Amazon S3
For me, it looked like this:
aws s3 cp s3://my-bucket-name s3://my-bucket-name --recursive --acl public-read --metadata-directive REPLACE --cache-control max-age=43200000
The command basically copies the entire bucket onto itself while adding the cache-control max-age=43200000 header to each object in the process.
This works for all existing files, but will not change anything for future changes or additions. You'd have to run this again every so often to catch new stuff and/or write code to set your object headers when saving the object to the bucket. Apparently there are people that have had luck with this. Not me.
Thankfully, I found this post:
https://www.neontsunami.com/posts/caching-variants-with-activestorage
This monkey-patch basically changes ActiveStorage::RepresentationsController#show to use Rails action caching for variants. Take a look. If you're having similar issues, it's worth the read.
There are drawbacks. For my case, they were not a problem, so this is the solution I went with.
I've successfully uploaded, via Paperclip, images to the RackSpace cloudfile storage, and they appear correctly within subsequent webpages when I'm using the CDN url.
However, I can't figure out why Paperclip is not showing the files if I do not use CDN enabled cloud files.
Paperclip returns (via its 'url' method for the attachment) the more usual /attachments/fred/1/image/123.jpg path, however that results in a broken image as there is no actual file stored at that url - its in RS cloud file storage.
I'm not sure whether
a) Paperclip is supposed to give me a url to non-cdn location
b) Paperclip provides a url which results in it then responding at that url to provide the raw image data
c) Something completely different to a) and b)
If someone could please shed some light on what url I'm supposed to get back from Paperclip for non CDN enabled RackSpace stored files I think it would help steer me in the correct direction.
Thanks.
Rackspace Cloud Files has the ability to download files without a CDN, but after researching it paperclip and fog do not currently support this.
Paperclip supports both CDN access as well as downloading files using a temporary url (sans CDN). I was going to suggest using a temporary url, however, the get_http_url method paperclip uses to retrieve this url isn't currently implemented for Rackspace.
I have created a fog issue to address this https://github.com/fog/fog/issues/2103.
My application is using Rails 2 backend, Heroku for hosting, Paperclip for file uploads, and Amazon S3 for file storage.
Right now users can upload files with paperclip + s3 - this works flawlessly. After upload, an icon appears on their dashboard, linked to the file location (in s3 bucket). When the icon is clicked, the browser opens the file in a new window (for most file types - PDF, MP3, img, etc). Instead of opening, I want the file to be automatically downloaded when the user clicks the file's icon (like Gmail attachments). The solution should be able to work for any file type and cross-browser.
Is there a helper to do this in rails, or is javascript needed? I'm really stuck on this one so anything to point me in the right direction would be greatly appreciated. Thanks!
Please try the following:
class Test < ActiveRecord::Base
has_attached_file :testfile,
:storage => :s3,
# All your S3 config
:s3_headers => {"Content-Disposition" => "attachment"}
end
This should tell the Paperclip Gem to set the "Content-Disposition" header to the value "attachment" for newly uploaded files.
Note that you have to manually edit the already uploaded file, e.g. with Cyberduck or another FTP Client.
When you transfer the file, you need to set a Content-Disposition header with a value of attachment; filename=yourfilename.pdf. If it's transfered directly from S3, you'll need to tell S3 to set the Content-Disposition headers as well. Possibly also Content-Type.
Note that if you tell S3 to associate a Content-Disposition header, it will always transmit this header.
FWIW, here's Amazon's documentation on doing a PUT for an Object: http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUT.html