Question

So this seems like it should be quite easy... everyone is saying just to use config.asset_host. When I set that though, all the links inside my app still point to S3.

CarrierWave.configure do |config|

  config.storage = :fog

  config.fog_credentials = {
    :provider              => 'AWS',
    :aws_access_key_id     => AWS_ACCESS_KEY_ID,
    :aws_secret_access_key => AWS_SECRET_ACCESS_KEY,
    :region                => 'us-east-1'
  }

  config.fog_authenticated_url_expiration = 3.hours

  config.asset_host     = "http://xyz123.cloudfront.net"
  config.fog_directory  = S3_BUCKET_NAME
  config.fog_public     = false
  config.fog_attributes = {
    'Cache-Control' => "max-age=#{1.year.to_i}"
  }
end

here is how I call my files...

image_tag book.attachments.first.filename.file.authenticated_url(:thumb175)

It looks to me like public_url prepends the proper host, but it takes 0 arguments... so how am I supposed to pass the proper response-content-disposition and response-content-type and the link expire time?

Was it helpful?

Solution 2

I think you found this for yourself, but public urls will not expire. If you want that you'll need to use authenticated urls. For public urls I think you can simply get the url and append whatever query params you would like, at least for now. If that works well for you, we can certainly see about patching things to do the right thing.

OTHER TIPS

I had the same problem and spent far too long figuring out the answer! It turns out that when you set fog_public = false CarrierWave will ignore config.asset_host. You can demo this by setting config.fog_public = true: your URLs will now be CloudFront URLs rather than S3 URLs. This issue has been raised previously:

https://github.com/carrierwaveuploader/carrierwave/issues/1158 https://github.com/carrierwaveuploader/carrierwave/issues/1215

In a recent project I was happy using CarrierWave to handle uploads to S3, but wanted it to return a signed CloudFront URL when using Model.attribute_url. I came up with the following (admittedly ugly) workaround that I hope others can benefit from or improve upon:

Add the 'cloudfront-signer' gem to your project and configure it per the instructions. Then add the following override of /lib/carrierwave/uploader/url.rb in a new file in config/initializers (note the multiple insertions of AWS::CF::Signer.sign_url):

module CarrierWave
      module Uploader
        module Url
          extend ActiveSupport::Concern
          include CarrierWave::Uploader::Configuration
          include CarrierWave::Utilities::Uri

          ##
          # === Parameters
          #
          # [Hash] optional, the query params (only AWS)
          #
          # === Returns
          #
          # [String] the location where this file is accessible via a url
          #
          def url(options = {})
            if file.respond_to?(:url) and not file.url.blank?
              file.method(:url).arity == 0 ? AWS::CF::Signer.sign_url(file.url) : AWS::CF::Signer.sign_url(file.url(options))
            elsif file.respond_to?(:path)
              path = encode_path(file.path.gsub(File.expand_path(root), ''))

              if host = asset_host
                if host.respond_to? :call
                  AWS::CF::Signer.sign_url("#{host.call(file)}#{path}")
                else
                  AWS::CF::Signer.sign_url("#{host}#{path}")
                end
              else
                AWS::CF::Signer.sign_url((base_path || "") + path)
              end
            end
          end

        end # Url
     end # Uploader
end # CarrierWave

Then override /lib/carrierwave/storage/fog.rb by adding the following to the bottom of the same file:

require "fog"

module CarrierWave
  module Storage
    class Fog < Abstract
       class File
          include CarrierWave::Utilities::Uri
          def url
             # Delete 'if statement' related to fog_public
             public_url
          end
       end
    end
  end
end

Lastly, in config/initializers/carrierwave.rb:

config.asset_host = "http://d12345678.cloudfront.net"

config.fog_public = false

That's it. You can now use Model.attribute_url and it will return a signed CloudFront URL to a private file uploaded by CarrierWave to your S3 bucket.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top