Paperclip, S3, Rails—Aws::S3::Errors::InvalidArgument (): - ruby-on-rails

As the title suggests, I'm using paperclip and S3 with Rails. When I try to create a record that has an image, I get this error:
[paperclip] saving interactives/5/images/original/Havaneser_Anton.jpg
(6.6ms) ROLLBACK
Completed 500 Internal Server Error in 2021ms (ActiveRecord: 86.8ms)
Aws::S3::Errors::InvalidArgument ():
I don't know what's going on, other than "It's not working"...
Here is my development.rb configuration:
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
config.paperclip_defaults = {
storage: :s3,
s3_permissions: :public,
s3_region: ENV['AWS_REGION'],
s3_credentials: {
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
bucket: ENV['AWS_S3_BUCKET']
},
s3_protocol: 'https',
s3_host_name: "s3-#{ENV['AWS_REGION']}.amazonaws.com",
path: ":class/:id/:attachment/:style/:filename"
}
My Model looks like this:
class Interactive < ApplicationRecord
belongs_to :project
has_attached_file :image, styles: { low_res: "10%", medium: "300x300>", thumb: "300x250>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/

Check your s3_permissions: :public, the value for this option should be one of the "Canned ACL" permissions from here. :public does not appear to be an option!

Related

Paperclip does not show image but instead shows title with amazon s3 in rails?

I am using paperclip and amazon s3 to store images for my website. Everything is working correctly without s3 in development mode but when I try to use s3 it shows me the title of the image and not the image. I have copied what is in the heroku guide https://devcenter.heroku.com/articles/paperclip-s3.
This is the gemfile
gem 'paperclip'
gem 'aws-sdk', '~> 2.3'
this is in profile.rb in class profile
has_attached_file :avatar,
:styles => { :medium => "300x300>", :thumb => "100x100>" },
:default_url => ":style/missing.jpg"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
this is in production.rb
config.paperclip_defaults = {
storage: :s3,
s3_host_name: "s3-#{ENV['AWS_REGION']}.amazonaws.com",
: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'),
}
}
views
<%= image_tag #user.profile.avatar.url(:medium) %>
i have copied the heroku guide and added the host name and s3 protocol bit. whats wrong here?
I have followed the heroku guide and was successfully able to upload the user image to S3 using paperclip in development env and I can also see the image in users's profile.
My Gemfile:
gem 'paperclip'
gem 'aws-sdk-s3'
My development.rb
config.paperclip_defaults = {
storage: :s3,
s3_host_name: "s3.#{ENV['AWS_REGION']}.amazonaws.com",
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'),
}
}
you have this (this might have caused an issue):
s3_host_name: "s3-#{ENV['AWS_REGION']}.amazonaws.com",
I have this (a dot after s3):
s3_host_name: "s3.#{ENV['AWS_REGION']}.amazonaws.com",
My user.rb is same as yours
has_attached_file :avatar,
:styles => { :medium => "300x300>", :thumb => "100x100>" },
:default_url => ":style/missing.jpg"
# Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
My show.html.erb
<%= image_tag #user.avatar.url(:medium) %>
I am using rails 5.2 version and with above code it works for me. Also do check whether your S3 bucket has public access to objects.

Paperclip - Upload to different S3 URLs from Different models

I had a model from which I used paperclip and stored to S3.
In paperclip.rb
bucket_name = (Rails.env != 'production') ? "mcds_staging_fulltext" : 'mcds_fulltext'
Paperclip::Attachment.default_options.merge!({
storage: :s3,
s3_credentials: {
bucket: bucket_name
},
url: "#{CUSTOMER}/static_cover_images/:style/:basename.:extension",
path: "#{CUSTOMER}/static_cover_images/:style/:basename.:extension"
})
model1.rb
has_attached_file :cover_image, styles: { :original => ["100%"], :thumbnail => ["100*100", :png] }
validates_attachment_content_type :cover_image, content_type: /\Aimage\/.*\Z/, message: 'Invalid Content Type. Please upload jpg/jpeg/png/gif'
validates_attachment_size :cover_image, :in => 0.megabytes..5.megabytes, :message => 'must be smaller than 5 MB'
this works poperly and store my images in S3 in correct location.
Now I have another model from where I need to upload a paperclip attachment to a different S3 Location.
In model2.rb
has_attached_file :xslt
Paperclip::Attachment.default_options.merge!({url: "#{CUSTOMER}/xslts/:style/:basename.:extension"})
validates_attachment_content_type :xslt, content_type: "application/xslt+xml", message: 'Invalid Content Type. Please upload jpg/jpeg/png/gif'
validates_attachment_size :xslt, :in => 0.megabytes..5.megabytes, :message => 'must be smaller than 5 MB'
but this attachment still stores to my model1 S3 and not in the url specified in model2.
What am I doing wrong?
I completely removed paper_clip.rb file and added paper_clip configurations in therespective models.
model1:
has_attached_file :file1,
storage: :s3,
s3_credentials: {
bucket: bucket_name
},
url: "#{CUSTOMER}/cover_images/:style/:basename.:extension",
path: "#{CUSTOMER}/cover_images/:style/:basename.:extension"
model2:
has_attached_file :file2,
storage: :s3,
s3_credentials: {
bucket: bucket_name
},
url: "#{CUSTOMER}/file2_folder/:style/:basename.:extension",
path: "#{CUSTOMER}/file2_folder/:style/:basename.:extension"
this stores theattachment correctly in differen S3 folders.

Custom URL with Paperclip and AWS S3

We're using Paperclip with the aws-sdk gem to store and display images in our Rails app:
class User < ActiveRecord::Base
has_attached_file :image,
storage: :s3,
s3_credentials: 'config/s3.yml',
s3_protocol: :https,
styles: {
curriculum: '120x120>',
medium: '600x600>',
thumb: '200x200>'
},
default_url: 'missing_photo.png'
end
If I then use <%= image_tag current_user.image.url %> in an html.erb file, I get the following HTML: <img src="https://s3.amazonaws.com/<my_bucket>/users/images/000/000/001/medium/my_image.png?1419989041">.
How do I get that https://s3.amazonaws.com/<my_bucket> to be a custom URL like https://example.com? I have my domain all setup in Cloudfront along with its SSL certificate.
I looked up in the Paperclip S3 Storage documentation. There's a :url option, but nothing I write for that option seems to work.
I just ran across this problem and here are the settings I had to use
:s3_host_alias => "s3.example.com",
:url => ":s3_alias_url",
:path => ":class/:attachment/:id.:style.:extension"
From this link, I learned that, in addition to :s3_host_alias and :url, you have to specify path so you don't get
Paperclip::InfiniteInterpolationError
Kinda works out well because the default paperclip path is kinda wonky anyways.
Update
I put together an example and was able to get it working with the following:
class User < ActiveRecord::Base
has_attached_file :profile_picture,
styles: { :medium => "300x300>", :thumb => "100x100>" },
path: 'users/:attachment/:style-:hash.:extension',
hash_secret: "94dfda08e2ed473257345563594dfda08e2ed473257345563594dfda08e2ed473257345563594dfda08e2ed4732573455635",
default_url: "/images/:style/missing.png",
storage: :s3,
s3_protocol: 'http',
url: ':s3_alias_url',
s3_host_alias: 'distro1234.cloudfront.net',
s3_credentials: {
access_key_id: 'access_id',
secret_access_key: 's3cr3tK3y!',
acl: 'private',
bucket: 'my-bucket',
bucket_url: 'https://my-bucket.s3.amazonaws.com',
}
validates_attachment_content_type :profile_picture, :content_type => /\Aimage\/.*\Z/
end
And the following Gemfile:
gem 'paperclip'
gem 'aws-sdk', '~> 1.5.7'
Rails console:
=> u.profile_picture.url
=> "http://distro1234.cloudfront.net/users/profile_pictures/original-95eb509f9c81a341945a5a65e59e81880a739d39.jpg?1429638820"
Try something like this:
has_attached_file :image,
storage: :s3,
s3_credentials: 'config/s3.yml',
s3_protocol: :https,
styles: {
curriculum: '120x120>',
medium: '600x600>',
thumb: '200x200>'
},
url: ':s3_alias_url',
s3_host_alias: 'example.com',
default_url: 'missing_photo.png'

Paperclip : wrong bucket being used from yml

This has worked before, or so I believe.
For some reason, in my development environment, and even staging, Paperclip is using my production bucket instead of the development bucket.
Here is the part of the user model that relates to it
has_attached_file :avatar,
storage: :s3,
s3_credentials: "#{Rails.root}/config/s3.yml",
s3_permissions: :private,
path: "/:style/:id/:filename",
s3_protocol: "https",
styles: { medium: "300x300#", thumb: "100x100#", icon: "26x26#" },
default_url: ":style/ico_missing_user.png"
And here, my yml file:
common: &common
access_key_id: <%= ENV['S3_KEY'] %>
secret_access_key: <%= ENV['S3_SECRET'] %>
development:
<<: *common
bucket: mydevbucket
staging:
<<: *common
bucket: mystagingbucket
production:
<<: *common
bucket: myprodbucket
What am i doing wrong ?
I added "load_config.rb" file to my initializers directory:
load_config.rb
S3_CONFIG = YAML.load_file("#{::Rails.root}/config/s3.yml")[Rails.env]
and started using S3_CONFIG instead of "#{Rails.root}/config/s3.yml"
has_attached_file :avatar,
storage: :s3,
s3_credentials: S3_CONFIG,
s3_permissions: :private,
path: "/:style/:id/:filename",
s3_protocol: "https",
styles: { medium: "300x300#", thumb: "100x100#", icon: "26x26#" },
default_url: ":style/ico_missing_user.png"
The solution above worked fine to set the bucket, but then I started having a problem with paperclip when uploading files, saying ECONN:Aborted.
The following is what i have understood to work :
has_attached_file :avatar,
storage: :s3,
:s3_credentials => "#{Rails.root}/config/s3.yml",
:bucket => ENV['S3_BUCKET'],
s3_permissions: :private,
path: "/:style/:id/:filename",
s3_protocol: "https",
styles: { medium: "300x300#", thumb: "100x100#", icon: "26x26#" },
default_url: ":style/ico_missing_user.png"
Notice I separated the bucket from the credentials. I did this inspired on the rdocs for paperclip, and on the following sample

get broken pipe while uploading image to s3 amazon using paper clip

I get a broken pipe error while uploading image to s3 amazon using paper clip
My Model:
has_attached_file :avatar, :styles => { :small => "100x100#", :large => "500x500>" },
:processors => [:cropper],
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:path => "/:style/:id/:filename",
:bucket => "shahbunder"
My s3.yml:
development:
bucket: xxx
access_key_id: xxx
secret_access_key: xxx
test:
bucket: xxx
access_key_id: xxx
secret_access_key: xxx
production:
bucket: xxx
access_key_id: xxx
secret_access_key: xxx
Note for people searching for a solution to an error that crosses between this and ERRCONNRESET - Response time skewed - your server clock is not synchronized with Amazon correctly.
This error occurs if you type your bucket name using "/" (ex: "bucket_name/"), use only the name (ex: "bucket_name").
I believe this is usually because your s3 credentials are wrong. But here are 2 different things you can try:
script/plugin install git://github.com/thoughtbot/paperclip.git (installing paperclip as a plugin instead of a gem has helped some)
gem install right_aws right_http_connection (make sure you are firing off your request correctly)
Try using Fog instead, I don't know if it's still undocumented or what:
Example (fit to your needs):
has_attached_file :media,
storage: :fog,
hash_secret: Settings.aws.uploader.hash_secret,
use_timestamp: Settings.aws.uploader.use_timestamps_in_url,
fog_credentials: Settings.aws.uploader.fog.to_hash,
fog_public: Settings.aws.uploader.public_files,
fog_directory: Settings.aws.s3.bucket_cname,
fog_host: "http://s.my.com",
default_url: "media/system/not_available.mp3",
hash_data: ":class/:attachment/:id/:style/:updated_at",
path: ":root_path/:id_partition",
#only_process:
processors: [:audio_thumbnail],
styles: { small: ['36x36#', :jpg], medium: ['72x72#', :jpg], large: ['115x115#', :jpg] },
skip_updated_at: true

Resources