Ruby on Rails with Figaro and Paperclip - ruby-on-rails

I'm using localhost right now and installed the Figaro gem to help me test using Paperclip with my S3 bucket. When I try to upload something, I get this message:
missing required :bucket option
In development.rb I inserted the following code:
config.paperclip_defaults = {
storage: :s3,
s3_credentials: {
bucket: :ENV['AWS_BUCKET'],
access_key_id: :ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: :ENV['AWS_SECRET_ACCESS_KEY']
}
}
And then I placed the following code in the Figaro-generated application.yml file:
development:
AWS_BUCKET: (the actual name of my bucket)
AWS_ACCESS_KEY_ID: (the actual access key)
AWS_SECRET_ACCESS_KEY: (etc)
I will say that when I declare what the bucket is directly into the model I'm using for this, it does seem to work (a new folder is generated in my bucket) but the image never actually appears in the destination (perhaps a separate issue or perhaps not).
I know I am missing something obvious here, I'm probably not doing something right. Using Rails v4 with aws-sdk v1.34 and Figaro v0.7.0. Thanks to anyone who can help me.

I think there is just a syntax typo. ENV is a variable; it's a hash and not a symbol. Just remove the : from in front of ENV. It should be:
config.paperclip_defaults = {
storage: :s3,
s3_credentials: {
bucket: ENV['AWS_BUCKET'],
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
}
}

Further to your comment, this is live code which is 100% working for us right now:
config.paperclip_defaults = {
storage: :s3,
s3_host_name: 's3-eu-west-1.amazonaws.com',
s3_credentials: {
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
},
bucket: ENV['S3_BUCKET_NAME']
}
Also make sure you restart your rails server each time you change these details. Reason being the config files are loaded at initialization, and maintained for the server's session

Related

AWS Access Key not working in rails app

I have a rails app setup with paperclip and aws-sdk
My aws.yml file is below:
development:
access_key_id: ENV['AWS_ACCESS_KEY_ID']
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
production:
access_key_id: ENV['AWS_ACCESS_KEY_ID']
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
My development.rb file is here:
config.paperclip_defaults = {
:storage => :s3,
:s3_credentials => {
:bucket => ENV['AWS_BUCKET']
}
}
I'm 100% sure my keys are correct. I've double, triple and quadruple checked the keys. I first tried an Iam user key, but that didn't work, then I tried creating a root key and that didn't work either. I'm back to using a brand new Iam user key and that user has full S3 access.
/config/initializers/algoliasearch.rb uses an environment variable just fine:
AlgoliaSearch.configuration = { application_id: 'xxxxxx', api_key: ENV['algolia_admin_api_key'] }
Still, though, when I try to upload a file in my development environment I get the InvalidAccessKey error from aws. I haven't tried it on production yet because that's using the same keys (just the bucket name is different).
Am I using the wrong keys? Or is something preventing my key from being accessed? I can't find anything telling me how to set my keys up properly and I'm completely lost. I know I got this working before and can't remember there being any other steps.
I figured out the solution: I had to add the s3 credentials to the production.rb and development.rb environment files:
# development.rb
config.paperclip_defaults = {
:storage => :s3,
:s3_credentials => {
:bucket => ENV['AWS_BUCKET'],
:access_key_id => ENV['HOMEIN_AWS_ACCESS_KEY_ID'],
:secret_access_key => ENV['HOMEIN_AWS_SECRET_ACCESS_KEY']
}
}
They're both the same, except for the bucket name.
I feel like there's a more elegant solution that I don't know of, though...

Ruby on Rails - AWS-SDK configuration file

I'm using AWS-SDK gem in my Rails project, and I want a kind-of initializer file to connect directly to my repo and make changes directly in the Rails console, something like this:
# At config/initializers/aws.rb
Aws::S3::Client.new(
:access_key_id => 'ACCESS_KEY_ID',
:secret_access_key => 'SECRET_ACCESS_KEY'
)
I've looked for documentation or tutorials but it's not clear for me. How do I do it? Thank you!
i think you can try like this
put this in aws.rb
AWS.config(
:access_key_id => ENV['ACCESS_KEY_ID'],
:secret_access_key => ENV['SECRET_ACCESS_KEY']
)
and when you initialize the object wherever you need, will call the configuration
s3 = AWS::S3.new
To share configuration between AWS service client in a Rails application, configure the AWS SDK for Ruby from a config initializer.
# config/initializers/aws-sdk.rb
Aws.config.update(
credentials: Aws::Credentials.new('access-key-id', 'secret-access-key'),
region: 'us-east-1',
)
Now you can construct a client object from any service without any options:
s3 = Aws::S3::Client.new
ec2 = Aws::EC2::Client.new
Please note, you should avoid hard-coding credentials into your application. This can be a security risk if your source code is accessed and it makes it difficult to rotate credentials.
I recommend using hands-off configuration via ENV['AWS_ACCESS_KEY_ID'] and ENV['AWS_SECRET_ACCESS_KEY'], or an EC2 instance profile.
Finally, I've found the solution:
Create the file aws.rb in your /config/initializers folder.
In aws.rb write:
S3Client = Aws::S3::Client.new(
access_key_id: 'ACCESS_KEY_ID',
secret_access_key: 'SECRET_ACCESS_KEY',
region: 'REGION'
)
That's it. Thank you all for your answers!
Also with aws-sdk-rails (1.0.0)
# config/initializers/aws.rb
Aws.config[:credentials] = Aws::Credentials.new(ENV['AWS_ACCESS_KEY_ID'], ENV['AWS_SECRET_ACCESS_KEY'])
TRY THIS CONFIGURATION:-
in config/intitalizers/s3.rb
Paperclip.interpolates(:s3_eu_url) { |attachment, style|
"#{attachment.s3_protocol}://s3-eu-west-1.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
}
config/initializers/paperclip.rb
require 'paperclip/media_type_spoof_detector'
module Paperclip
class MediaTypeSpoofDetector
def spoofed?
false
end
end
end
Paperclip::Attachment.default_options[:url] = ':s3_domain_url'
Paperclip::Attachment.default_options[:path] = '/:class/:id/:style/:filename'
S3_CREDENTIALS = Rails.root.join("config/s3.yml")
/config/s3.yml
development:
bucket: development_bucket
access_key_id: AKIA-----API KEYS---------MCLXQ
secret_access_key: qTNF1-------API KEYS--------DTy+rPubaaG
production:
bucket: production_bucket
access_key_id: AKI-----API KEYS--------LXQ
secret_access_key: qTNF1dW---API KEYS---+rPubaaG
hope you have gem "aws-sdk"in the Gemfile
add you asset in model
has_attached_file :avatar,
:styles => {:view => "187x260#"},
:storage => :s3,
:s3_permissions => :private,
:s3_credentials => S3_CREDENTIALS
verify using rails console with static image in public
Image.create(avatar: File.new("#{Rails.root}/public/images/colorful_blue.jpg"))

Rails ArgumentError (missing required :bucket option) fixes not working?

My Rails app is hosted on Heroku but I need to get Paperclip working locally so I can upload photos in testing. I'm really close, but I'm stuck on the "missing required :bucket option" error.
I've tried moving around settings in my environment files as well as well as adding a config/application.yml file with my AWS credentials in it, but no dice.
Here's my config from development.rb (looks the same in 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']
}
}
I've tried moving :bucket attribute outside of :s3_credentials but it didn't change anything. Application.yml looks like this:
AWS_ACCESS_KEY_ID="xxxxxxxxxxxxxxxxx"
AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxx"
S3_BUCKET_NAME="xxxxxx"
I also installed the dot-env gem and added an s3.env file to the index of my app which contains the same credentials as above, but even that hasn't worked. Nor did adding my Paperclip config inline with the has_attached_file in my model.
What do I do??
Alternatively, if someone runs into this problem and doesn't want to use a .env file, the following works.
Assuming your bucket is hosted in the US region, put a file called aws.yml under the config dir. The file should be in the following format:
development:
access_key_id: AWS_ACCESS_KEY_ID
secret_access_key: AWS_SECRET_KEY_ID
production:
access_key_id: AWS_ACCESS_KEY_ID
secret_access_key: AWS_SECRET_KEY_ID
In your model:
class Model < ActiveRecord::Base
has_attached_file :avatar, styles: {
thumb: '100x100>',
square: '200x200#',
medium: '300x300>'}, :storage => :s3,
:s3_credentials => "#{Rails.root}/config/aws.yml",
:bucket => "your_bucket_name"
validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
Replace your_bucket_name with the name of your actual bucket.
Gemfile:
gem 'aws-sdk', '< 2.0'
Under Environments, production and development:
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']
}
}
To put it in production on Heroku, you have to set the following using the terminal:
$ heroku config:set S3_BUCKET_NAME=your_bucket_name
$ heroku config:set AWS_ACCESS_KEY_ID=your_access_key_id
$ heroku config:set AWS_SECRET_ACCESS_KEY=your_secret_access_key
Your Application.yml file doesn't look like YAML. It should look like this:
AWS_ACCESS_KEY_ID: "xxxxxxxxxxxxxxxxx"
AWS_SECRET_ACCESS_KEY: "xxxxxxxxxxxxxxxxxxxx"
S3_BUCKET_NAME: "xxxxxx"
If you are loading the yml file like they advise here you'll want your yml file to look like this:
development:
AWS_ACCESS_KEY_ID: "xxxxxxxxxxxxxxxxx"
AWS_SECRET_ACCESS_KEY: "xxxxxxxxxxxxxxxxxxxx"
S3_BUCKET_NAME: "xxxxxx"
You need a way to set the environment variables for your app in your development environment. Using Application.yml or .env file should work, but you probably don't need both.

Paperclip uploads on Heroku using S3

I'm sorry to rehash an old gripe but I'm at my wits end and not sure where to go next. I am using Paperclip on Heroku and have S3 uploads configured. I was able to get things working in my local development environment but once it's running on Heroku I run into this error:
AWS::S3::Errors::PermanentRedirect (The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.
I've googled this error and read through the Heroku documentation and I believe I have everything set up correctly. I initially thought that my problems stemmed from having my bucket in the s3-us-west-1.amazonaws.com region, but I'm not convinced anymore.
Here are the relevant parts of my Heroku config:
AWS_REGION: us-west-1
S3_BUCKET_NAME: my-super-awesomely-amazing-bucket
From my config/environments/production.rb file:
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']
}
}
My paperclip.rb initialize file:
if Rails.env.production?
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-1.amazonaws.com'
end
And my paperclip config from the relevant model:
has_attached_file :document,
:styles => { },
:default_url => "/image_styles/:style/missing.png"
So...what am I doing wrong here? At this point I'm sure I've missed something obvious but I'm stumped on where to go from here. I feel like I've assiduously configured everything and yet that PermanentRedirect error keeps coming up.
Bucket
This might not be the direct solution, but we've found that you have to include the bucket option outside of your s3_credentials block:
#config/environments/production.rb
config.paperclip_defaults = {
storage: :s3,
s3_host_name: 's3-eu-west-1.amazonaws.com',
s3_credentials: {
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
},
bucket: ENV['S3_BUCKET_NAME']
}
This is working 100% for us on Heroku, but whether it wil work for you (as your bucket is in a different region) is a different matter
If you need more help, ask a comment and I'll gladly give you some ideas
Try this link http://adamthedeveloper.blogspot.in/2014/02/awss3permanentredirect-bucket-you-are.html . Previously this happened to Europe region buckets only and get resolved by setting AWS::S3::DEFAULT_HOST. Hope this solve your issue.

Associate object to pre-existing file on S3, using Paperclip

I have a file already on S3 that I'd like to associate to a pre-existing instance of the Asset model.
Here's the model:
class Asset < ActiveRecord::Base
attr_accessible(:attachment_content_type, :attachment_file_name,
:attachment_file_size, :attachment_updated_at, :attachment)
has_attached_file :attachment, {
storage: :s3,
s3_credentials: {
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
},
convert_options: { all: '-auto-orient' },
url: ':s3_alias_url',
s3_host_alias: ENV['S3_HOST_ALIAS'],
path: ":class/:attachment/:id_partition/:style/:filename",
bucket: ENV['S3_BUCKET_NAME'],
s3_protocol: 'https'
}
end
Let's say the path is assets/attachments/000/111/file.png, and the Asset instance I want to associate with the file is asset. Referring at the source, I've tried:
options = {
storage: :s3,
s3_credentials: {
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
},
convert_options: { all: '-auto-orient' },
url: ':s3_alias_url',
s3_host_alias: ENV['S3_HOST_ALIAS'],
path: "assets/attachments/000/111/file.png",
bucket: ENV['S3_BUCKET_NAME'],
s3_protocol: 'https'
}
# The above is identical to the options given in the model, except for the path
Paperclip::Attachment.new("file.png", asset, options).save
As far as I can tell, this did not affect asset in any way. I cannot set asset.attachment.path manually.
Other questions on SO do not seem to address this specifically.
"paperclip images not saving in the path i've set up", "Paperclip and Amazon S3 how to do paths?", and so on involve setting up the model, which is already working fine.
Anyone have any insight to offer?
As far as I can tell, I do need to turn the S3 object into a File, as suggested by #oregontrail256. I used the Fog gem to do this.
s3 = Fog::Storage.new(
:provider => 'AWS',
:aws_access_key_id => ENV['AWS_ACCESS_KEY_ID'],
:aws_secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
)
directory = s3.directories.get(ENV['S3_BUCKET_NAME'])
fog_file = directory.files.get(path)
file = File.open("temp", "wb")
file.write(fog_file.body)
asset.attachment = file
asset.save
file.close
Paperclip attachments have a copy_to_local_file() method that allows you to make a local copy of the attachment. So what about:
file_name = "temp_file"
asset1.attachment.copy_to_local_file(:style, file_name)
file = File.open(file_name)
asset2.attachment = file
file.close
asset2.save!
Even if you destroy asset1, you now have a copy of the attachment saved by asset2 separately. You probably want to do this in a background job if you're doing many of them.
Credit to this answer too: How to set a file upload programmatically using Paperclip

Resources