Paperclip S3 - Can upload images but cannot view them - ruby-on-rails

I'm created a Rails app running on Heroku, with Paperclip and S3. I've managed to upload images to my S3 bucket through the site (I can see them show up in my bucket on the Amazon control panel).
But when I add an Image tag i.e. <%= image_tag x.photo.url %>, I get the following html (tags omitted here), with no image displayed!
img alt="Test_tree" src="http://s3.amazonaws.com/hiphotos/ads/photos/000/000/015/original/test_tree.jpg?1344661020"
Why can't I see the images even though they're in the bucket?

Create a file a called paperclip initializer:
# config/initializers/paperclip.rb
# We are actually setting this to 's3_domain_url',
# so it's not a placeholder for something else.
Paperclip::Attachment.default_options[:url] = ':s3_domain_url'
Paperclip::Attachment.default_options[:path] = '/:class/:attachment/:id_partition/:style/:filename'
Or you could also place this inside production.rb:
config.paperclip_defaults = {
:storage => :s3,
:s3_credentials => {
:bucket => ENV['S3_BUCKET_NAME'],
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
},
:url =>':s3_domain_url',
:path => '/:class/:attachment/:id_partition/:style/:filename',
}

Firstly, the url you are trying to use up there in your code is this:
http://s3.amazonaws.com/hiphotos/ads/photos/000/000/015/original/test_tree.jpg
When you visit that link in the browser, you see the following:
<message>
The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.
</Message>
<RequestId>810A6AE1D141304C</RequestId>
<Bucket>hiphotos</Bucket>
<HostId>
XXZ+s+slgZLsRWy5NiU/G0yAKBLftw0oT2dDKpas532qXJEPSrISVPqfZsEgpb2J
</HostId>
<Endpoint>hiphotos.s3.amazonaws.com</Endpoint>
So if we modify the url using the correct endpoint we get this:
http://hiphotos.s3.amazonaws.com/ads/photos/000/000/015/original/test_tree.jpg
Which does return the correct image.
If you are using European buckets, this can happen, and it might be the fault of the gem you are using to push things to s3.
There are loads of articles on how to get Paperclip, S3 and European buckets to play nicely together.
I have found though, that since I started using the asset_sync gem, which uses Fog instead of aws-s3 gem, I don't have any more trouble with paperclip and S3.
So I suspect Fog has something to do with making this problem go away for me. I'd recommend switching to it, if you're using something else.

Related

Can't get Paperclip to set my S3 URLs properly

I'm using paperclip and aws-sdk gems in a Rails 4 app.
I define the :path option in my paperclip.rb config, with no :url option:
Paperclip::Attachment.default_options[:path] = ":class/:attachment/:id_partition/:style/:filename"
It saves my uploaded images like such:
http://s3.amazonaws.com/mybucket-development/profiles/avatars/000/000/026/original/image_file_name.png?1420575189
All fine, it gets saved to S3. However it refuses to let me read the images for display, e.g. =profile.avatar.url(:medium). When I go to that URL in the browser it tells me to re-format it with the bucket name as a domain. Like:
http://mybucket-development.s3.amazonaws.com/profiles/avatars/000/000/026/original/image_file_name.png?1420575189
OK, not a problem either. I go to that URL, I can view my image. So now I need to figure out how to get Paperclip to format the URLs like this automatically. I read in the Paperclip docs that you just have to set
Paperclip::Attachment.default_options[:url] = ":s3_domain_url"
And that I also have to set the :path parameter or I will just get a Paperclip::Errors::InfiniteInterpolationError.
So I set my config file with both combined:
Paperclip::Attachment.default_options[:path] = ":class/:attachment/:id_partition/:style/:filename"
Paperclip::Attachment.default_options[:url] = ":s3_domain_url"
Not working... I try scrapping the paperclip.rb and putting it in config/environments/* But no matter what I do, it still saves the URLs without the domain with the bucket name in the path.
So two questions:
1) How can I get Paperclip to automatically format the saved URLs in domain style?
2) Or even better, how can I get S3 to accept the non-domain style URLs, the one that Paperclip is currently generating?
EDIT
So, if I add in the s3_host_name option then it saves the URLs domain style. So I have to have all 3 of:
Paperclip::Attachment.default_options[:url] = ':s3_domain_url'
Paperclip::Attachment.default_options[:path] = ":class/:attachment/:id_partition/:style/:filename"
Paperclip::Attachment.default_options[:s3_host_name] = 's3-us-west-2.amazonaws.com'
And it will save my URLs on the model like so:
http://mybucket-development.s3-us-west-2.amazonaws.com/profiles/avatars/000/000/026/original/image_file_name.png%3F1420580224
But now I see that I have a %3F encoding ("?") in the URL which messes it up.
Alright, so as mentioned in the above update, to get the domain-style URLs to be saved by Paperclip I have to include all 3 of the following in my paperclip.rb:
Paperclip::Attachment.default_options[:url] = ':s3_domain_url'
Paperclip::Attachment.default_options[:path] = ":class/:attachment/:id_partition/:style/:filename"
Paperclip::Attachment.default_options[:s3_host_name] = 's3-us-west-2.amazonaws.com'
I believe there is a related issue from recent gem upgrades, this produces URLs with encodings that won't work on their own.
So in my views I have had to add URI.unescape, such as
=image_tag URI.unescape(profile.avatar.url(:medium))
I could also set a callback on the model to replace the %3F with the "?" before save.
Strange issue with Paperclip... not sure what was going on. First app I've worked on where I encountered that issue.
In paperclip.rb
Paperclip::Attachment.default_options[:s3_host_name] = 's3-ap-south-1.amazonaws.com'
In production.rb
config.paperclip_defaults = {
storage: :s3,
s3_protocol: :https,
s3_credentials: {
bucket: ENV.fetch('S3_BUCKET_NAME'),
access_key_id: ENV.fetch('AWS_ACCESS_KEY_ID'),
secret_access_key: ENV.fetch('AWS_SECRET_ACCESS_KEY'),
s3_region: ENV.fetch('AWS_REGION')
}
This pretty much worked well for me with image_tag. It should work for you too.

Rails Paperclip returning wrong Cloudfront URL

I'm working on a Rails website that uses Paperclip to upload files to Amazon S3 and then serve them through Cloudfront. I've got the uploading working fine, and Cloudfront is serving the files properly, but for some reason ModelObj.attachment.url isn't working properly on my production server. It works fine on my development server (WEBrick under Windows 8) but is returning the wrong URL on the live site (LAMP with Phusion Passenger). It returns almost the right url, but instead of
http://[stuff].cloudfront.net/kidbooks/snds/5072_original.mp3?1393858446
I'm getting
http:///kidbooks/snds/5072_original.mp3?1393858446
It's configured as follows: In environment.rb:
Paperclip::Attachment.default_options.merge!({
:storage => :s3,
:bucket => APP_CONFIG['s3_bucket'],
:path => "/#{APP_CONFIG['s3_path']}/:attachment/:id_:style.:extension",
:s3_credentials => {
...
}
})
And in the model:
has_attached_file :snd,
:url => ':s3_alias_url',
:s3_host_alias => APP_CONFIG['cloudfront_domain']
APP_CONFIG is being set properly on both servers; I've checked. (Or at least, it's being set properly in the console on the live server; I guess I could check more directly. There doesn't appear to be anything relevant in environments/development.rb or production.rb. What's going wrong here, and how can I fix it?
(I found this question, which is close to what I need, but only involves S3.)
Update: Found something weird. Model.snd.options returns a hash that includes, among other things, :s3_host_alias=>nil. Maybe my model is somehow being loaded before my configuration files?
Aha, found it. For some reason my model is either being loaded before my config files, or the loader doesn't have access to APP_CONFIG. This meant that :s3_host_alias was being set to nil, which of course broke things. I moved :s3_host_alias => APP_CONFIG['cloudfront_domain'] from the model to environment.rb, and now it's working fine.
I have no idea why my model would be loading before my config files, though.

How to use Amazon S3 on Spree-2-2-stable

I need to configure my images on Amazon S3, but when I tried to do so under version 2-2-stable from Spree, I realized that this configuration were moved away from the admin panel.
I read somewhere that this configuration was creating some problems, and thus it was removed on 2-2. But I assume that the functionality is still working somehow.
When I try to add these configs to my config/initialize/spree.rb, I´m getting an error because these preferences are no longer existing.
preference :s3_access_key, :string
preference :s3_bucket, :string
preference :s3_secret, :string
These preferences are found on 2-1-stable but not on 2-2-stable
https://github.com/spree/spree/blob/2-1-stable/core/app/models/spree/app_configuration.rb
https://github.com/spree/spree/blob/2-2-stable/core/app/models/spree/app_configuration.rb
Is there any way how to get it working in order to use it together with Heroku?
Here is Spree's commit with the changes and some instruction as to how to make configuration changes.
https://github.com/spree/spree/commit/b1d6c5e4b9801d888cc76c05116b814945122207
My understanding is that you can still use paperclip to manage uploading to S3, which I have successfully done using their instructions. I have however had problems getting the save path on S3 to configure correctly. This might get you started ... in an environment config file put the following:
# Paperclip configs
config.paperclip_defaults = {
:storage => :s3,
:bucket => ENV['S3_BUCKET_NAME'],
:s3_credentials => {
:access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
}
}
I use environment variables for the S3 credentials, so yours will most likely be different. This chunk of code has made uploading files to S3 work, like I said I just can't force a specific file path on upload. Hope that helps.
EDIT - ADDITIONAL INFO:
I added the following to the spree.rb initializer to define a custom upload path and a custom url path.
# S3 upload path and url path configuration
Spree::Image.attachment_definitions[:attachment][:path] = 'products/:id/:style/:basename.:extension'
Spree::Image.attachment_definitions[:attachment][:url] = 'products/:id/:style/:basename.:extension'
To change default upload sizes you can override the Spree image decorator model. So under app/models add a spree directory and add a file named image_decorator.rb. You can then control the sizes with the following:
Spree::Image.class_eval do
attachment_definitions[:attachment][:styles] = {
:mini => '48x48>', # thumbs under image
:small => '350x700>', # images on category view
:product => '1024x768>', # full product image
:large => '600x600>' # light box image
}
end
Check out this page for specifics --> http://guides.spreecommerce.com/developer/logic.html
So to sum up, you can do all your general image/S3 configuration by updating your environment initializer, your Spree initializer and overriding the spree image_decorator model.

How can I handle user-uploaded photo files for a Rails app (using paperclip) on Heroku?

So I'm making a Rails app which allows Users to create Items, and each Item has an image attachment, which is handled through the Paperclip gem. The Paperclip gem, by default, saves photos to the public folder, both in original (and thumbnail) form.
I can see how this can get out of hand pretty fast in terms of storage space, given that photos can be fairly big.
My questions:
1) How much space will Heroku allow me to hold for images in the public folder?
2) If Heroku only allows you to hold a finite amount of data in this folder (which I'm sure it does), how can I handle photo storage for a site that will probably have a lot of images? Remotely perhaps? Compression? (Specifics would be nice, as I am completely new to image storage.)
Heroku has a read-only file system for your app. Use Amazon S3 to store your uploaded images. Paperclip has great support for S3. Check out this Heroku guide.
As Chris said, you'll want to use a third party service like S3 and if you do end up using Paperclip then you'll eventually have something like this example in your model.
has_attached_file :photo,
:styles => { :thumb=> "100x100", :small => "300x300" },
:storage => :s3,
:s3_credentials => "#{Rails.root.to_s}/config/s3.yml",
:path => "/:id/:style/:filename"
And in your config directory you'll have an s3.yml credentials file that would look like:
development:
bucket: blahblah
access_key_id: sfoi40j8elkfv08hwo
secret_access_key: DJyWuRtsfoi40j8elkfv08hwos0m8qt
production:
bucket: blahblah
access_key_id: sfoi40j8elkfv08hwo
secret_access_key: DJyWusfoi40j8elkfv08hwos0m8qt

paperclip doesn't create thumbnails on heroku

I've been trying to get paperclip to upload images to amazon s3, but all I get is the original file being uploaded. No thumbnails are generated. My model has this in it:
has_attached_file :screenshot, :styles => {
:thumb => "100x80>",
:medium => "195x150>",
:large => "390x300>"
},
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => ":attachment/:id/:style.:extension"
The original file is in fact uploaded, but none of thumbnails appear. If I copy the src of a thumb format image, for instance, I get
<Error>
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
<Key>screenshots/8/thumb.png</Key>
<RequestId>B8A408560070E836</RequestId>
−
<HostId>
HAHUCuNxGKVDvqE3GnhGT1RcBgFGUxa35kqXmyRE+ii60DJS6r22ChDr22cOeCea
</HostId>
</Error>
This is running on heroku, which forces me to use a service like amazon. Not a problem but all the documentation I can find makes this look straightforward. I can't find any dependencies (bundler is happy), and I've been using AWS for 2 years now, without these problems, on another site, with a different bucket on the same account. Is it a problem of connecting the bucket to the account? I'm using the same credentials as in the other site. Only the bucket changes.
A couple more things. The directories that are being created in the path of the image that is being uploaded are permissions 000 or whatever the aws equivalent is. Nobody is permitted to do anything.
using Rails 3.
I had the same problem and the answer lies in:
:path => ":attachment/:id/:style.:extension"
Instead of storing the images in the same folder_id with different names, use the same name for the image and use the style for folders. The above would translate into:
:path => ":attachment/:id/:style/:filename"
So instead of trying to generate something like:
avatars/13/thumb.png
avatars/13/medium.png
avatars/13/large.png
You get this:
avatars/13/thumb/my_pic.png
avatars/13/medium/my_pic.png
avatars/13/large/my_pic.png
I installed paperclip as a plugin, and everything works.
Don't forget to remove the gem from your Gemfile.

Resources