Carrierwave uploading with s3 and fog
Asked Answered
L

2

7

been trying to search the reason for this error for a long time and can't seem to find any...

So I have a rails app, and I utilize carrierwave for pictures uploading. I also want to utilize Amazon S3 for file upload storage in my app.

Initially as I am developing the app I allowed file uploads to be on the on :file, i.e.

image_uploader.rb

# Choose what kind of storage to use for this uploader:
  storage :file
# storage :fog

Now upon finishing up development and placing it live (I use heroku), I decided to change the carrierwave storage to S3 to test it locally.

image_uploader.rb

# Choose what kind of storage to use for this uploader:
# storage :file
storage :fog

However, now when I try to upload a picture (be it for user avatar, etc) I get this error:

Excon::Errors::Forbidden in UsersController#update
Expected(200) <=> Actual(403 Forbidden)
request => {:connect_timeout=>60, :headers=>{"Content-Length"=>74577, "x-amz-   acl"=>"private", "Content-Type"=>"image/png", "Date"=>"Sun, 26 Feb 2012 10:00:43 +0000",  "Authorization"=>"AWS AKIAJOCDPFOU7UTT4HOQ:8ZnOy7X71nQAM87yraSI24Y5bSw=", "Host"=>"s3.amazonaws.com:443"}, :instrumentor_name=>"excon", :mock=>false, :read_timeout=>60, :retry_limit=>4, :ssl_verify_peer=>true, :write_timeout=>60, :host=>"s3.amazonaws.com", :path=>"/uploads//uploads%2Fuser%2Favatar%2F1%2Fjeffportraitmedium.png", :port=>"443", :query=>nil, :scheme=>"https", :body=>"\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x00\xC2\x00\x00\x00\xC3\b\x06\x00\x00\x00\xD0\xBD\xCE\x94\x00\x00\nCiCCPICC Profile\x00\x00x\x01\x9D\x96wTSY\x13\xC0\xEF{/\xBD\xD0\x12B\x91\x12z\rMJ\x00\x91\x12z\x91^E%$\
...
# The code you see above to the far right repeats itself a LOT
...
1@\x85\xB5\t\xFC_y~\xA6=:\xB2\xD0^\xBB~i\xBB\x82\x8F\x9B\xAF\xE7\x04m\xB2i\xFF\x17O\x94S\xF7l\x87\xA8&\x00\x00\x00\x00IEND\xAEB`\x82", :expects=>200, :idempotent=>true, :method=>"PUT"}
response => #<Excon::Response:0x007fc88ca9f3d8 @body="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>8EFA56C0DDDC8878</RequestId><HostId>1OxWXppSSUq1MFjQwvnFptuCM3gKOuKdlQQyVSEgvzzv4Aj+r2hSFM2UUw2NYyrR</HostId></Error>", @headers={"x-amz-request-id"=>"8EFA56C0DDDC8878", "x-amz-id-2"=>"1OxWXppSSUq1MFjQwvnFptuCM3gKOuKdlQQyVSEgvzzv4Aj+r2hSFM2UUw2NYyrR", "Content-Type"=>"application/xml", "Transfer-Encoding"=>"chunked", "Date"=>"Sun, 26 Feb 2012 10:00:47 GMT", "Connection"=>"close", "Server"=>"AmazonS3"}, @status=403>

And then it says this as well for my application trace:

app/controllers/users_controller.rb:39:in `update'

And my REQUEST parameters:

{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"DvADD1vYpCLcghq+EIOwVSjsfmAWCHhtA3VI5VGD/q8=",
"user"=>{"avatar"=>#<ActionDispatch::Http::UploadedFile:0x007fc88cde76f8     
@original_filename="JeffPortraitMedium.png",
@content_type="image/png",
@headers="Content-Disposition: form-data; name=\"user[avatar]\";   
filename=\"JeffPortraitMedium.png\"\r\nContent-Type: image/png\r\n",
@tempfile=#<File:/var/folders/vg/98nv58ss4v7gcbf8px_8dyqc0000gq/T/RackMultipart20120226- 19096-1ppu2sr>>,
"remote_avatar_url"=>"",
"name"=>"Jeff Lam ",
"email"=>"[email protected]",
"user_bio"=>"Tester Hello",
"shop"=>"1"},
"commit"=>"Update Changes",
"id"=>"1"}

Here's my users_controller.rb partial code:

def update
    @user = User.find(params[:id])
    if @user.update_attributes(params[:user]) 
        redirect_back_or root_path
        flash[:success] = "Your have updated your settings successfully."
    else
        flash.now[:error] = "Sorry! We are unable to update your settings. Please check your fields and try again."
        render 'edit'
    end
end

My image_uploader.rb code

# encoding: utf-8
class ImageUploader < CarrierWave::Uploader::Base

  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  # storage :file
  storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  # process :scale => [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  version :thumb do
    process resize_to_fill: [360, 250]
  end

  version :cover_photo_thumb do
    process resize_to_fill: [1170, 400]
  end

  version :event do
    process resize_to_fill: [550, 382]
  end

  version :product do
    process resize_to_fit: [226, 316]
  end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  def extension_white_list
    %w(jpg jpeg gif png)
  end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end 

  # fix for Heroku, unfortunately, it disables caching, 
  # see: https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Make-Carrierwave-work-on-Heroku
  def cache_dir
    "#{Rails.root}/tmp/uploads"
  end

end

Finally, my fog.rb file in the config/initializers

CarrierWave.configure do |config|
  config.fog_credentials = {
    :provider               => 'AWS',       # required
    :aws_access_key_id      => 'ACCESS_KEY',       # required
    :aws_secret_access_key  => 'SECRET_ACCESS_KEY/ZN5SkOUtOEHd61/Cglq9',       # required
    :region                 => 'Singapore'  # optional, defaults to 'us-east-1' 
  }
  config.fog_directory  = 'ruuva/'                     # required
  config.fog_public     = false                          # optional, defaults to true
end

I'm actually quite confused on some of the things in my fog.rb. Firstly, should I change my region to Singapore if I created a bucket called "ruuva", with region "Singapore" on my amazon s3 account?

Thank you to anyone that can help in advance!

Leatherleaf answered 26/2, 2012 at 10:13 Comment(2)
whatever it is, if you receive a 403 it's an authentication error. You need to investigate in that direction first.Babbittry
try to remove slash after ruuva, also change region to default one.Pachston
B
8

First make sure you use the right credentials by not setting custom region and custom directory (create a fake bucket for free in the default region)

Then I think you are not using the right name for the region. Try setting your region like this:

:region  => 'ap-southeast-1'
Bubbler answered 26/2, 2012 at 14:0 Comment(3)
Thank you! I did what you asked me to (check regions, did default bucket, etc) and somehow it worked! Also, in case anyone somehow faces the same problem: make sure to restart your development app server everytime you changed something in fog.rb! Newbie mistake, I know. :)Leatherleaf
S3 does not require region selection.Henze
It might have changed but a while ago S3 had a standard endpoint that redirected you to the proper region for a given bucket. So this was not ideal because each request was redirectedBubbler
M
5

We were facing the same problem and fixed that changing the user's permission associated to your access key, changing it to "Power User". Check if you need your user to be power user before put it into productions.

Monserratemonsieur answered 6/11, 2012 at 19:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.