module Paperclip::Storage::Fog

fog is a modern and versatile cloud computing library for Ruby. Among others, it supports Amazon S3 to store your files. In contrast to the outdated AWS-S3 gem it is actively maintained and supports multiple locations. Amazon's S3 file hosting service is a scalable, easy place to store files for distribution. You can find out more about it at aws.amazon.com/s3 There are a few fog-specific options for has_attached_file, which will be explained using S3 as an example:

Constants

AWS_BUCKET_SUBDOMAIN_RESTRICTON_REGEX

Public Class Methods

extended(base) click to toggle source
# File lib/paperclip/storage/fog.rb, line 42
def self.extended(base)
  unless defined?(Fog)
    begin
      require "fog"
    rescue LoadError => e
      e.message << " (You may need to install the fog gem)"
      raise e
    end
  end

  base.instance_eval do
    unless @options[:url].to_s.match(/\A:fog.*url\z/)
      @options[:path]  = @options[:path].gsub(/:url/, @options[:url]).gsub(/\A:rails_root\/public\/system\//, "")
      @options[:url]   = ":fog_public_url"
    end
    unless Paperclip::Interpolations.respond_to? :fog_public_url
      Paperclip.interpolates(:fog_public_url) do |attachment, style|
        attachment.public_url(style)
      end
    end
  end
end

Public Instance Methods

copy_to_local_file(style, local_dest_path) click to toggle source
# File lib/paperclip/storage/fog.rb, line 178
def copy_to_local_file(style, local_dest_path)
  log("copying #{path(style)} to local file #{local_dest_path}")
  ::File.open(local_dest_path, "wb") do |local_file|
    file = directory.files.get(path(style))
    return false unless file

    local_file.write(file.body)
  end
rescue ::Fog::Errors::Error => e
  warn("#{e} - cannot copy #{path(style)} to local file #{local_dest_path}")
  false
end
exists?(style = default_style) click to toggle source
# File lib/paperclip/storage/fog.rb, line 67
def exists?(style = default_style)
  if original_filename
    !!directory.files.head(path(style))
  else
    false
  end
end
expiring_url(time = (Time.now + 3600), style_name = default_style) click to toggle source
# File lib/paperclip/storage/fog.rb, line 157
def expiring_url(time = (Time.now + 3600), style_name = default_style)
  time = convert_time(time)
  http_url_method = "get_#{scheme}_url"
  if path(style_name) && directory.files.respond_to?(http_url_method)
    expiring_url = directory.files.public_send(http_url_method, path(style_name), time)

    if @options[:fog_host]
      expiring_url.gsub!(/#{host_name_for_directory}/, dynamic_fog_host_for_style(style_name))
    end
  else
    expiring_url = url(style_name)
  end

  expiring_url
end
flush_deletes() click to toggle source
# File lib/paperclip/storage/fog.rb, line 137
def flush_deletes
  @queued_for_delete.each do |path|
    log("deleting #{path}")
    directory.files.new(key: path).destroy
  end
  @queued_for_delete = []
end
flush_writes() click to toggle source
# File lib/paperclip/storage/fog.rb, line 107
def flush_writes
  @queued_for_write.each do |style, file|
    log("saving #{path(style)}")
    retried = false
    begin
      attributes = fog_file.merge(
        body: file,
        key: path(style),
        public: fog_public(style),
        content_type: file.content_type
      )
      attributes.merge!(@options[:fog_options]) if @options[:fog_options]
      directory.files.create(attributes)
    rescue Excon::Errors::NotFound
      raise if retried

      retried = true
      directory.save
      file.rewind
      retry
    ensure
      file.rewind
    end
  end

  after_flush_writes # allows attachment to clean up temp files

  @queued_for_write = {}
end
fog_credentials() click to toggle source
# File lib/paperclip/storage/fog.rb, line 75
def fog_credentials
  @fog_credentials ||= parse_credentials(@options[:fog_credentials])
end
fog_file() click to toggle source
# File lib/paperclip/storage/fog.rb, line 79
def fog_file
  @fog_file ||= begin
    value = @options[:fog_file]
    if !value
      {}
    elsif value.respond_to?(:call)
      value.call(self)
    else
      value
    end
  end
end
fog_public(style = default_style) click to toggle source
# File lib/paperclip/storage/fog.rb, line 92
def fog_public(style = default_style)
  if @options.key?(:fog_public)
    value = @options[:fog_public]
    if value.respond_to?(:key?) && value.key?(style)
      value[style]
    elsif value.respond_to?(:call)
      value.call(self)
    else
      value
    end
  else
    true
  end
end
parse_credentials(creds) click to toggle source
# File lib/paperclip/storage/fog.rb, line 173
def parse_credentials(creds)
  creds = find_credentials(creds).stringify_keys
  (creds[RailsEnvironment.get] || creds).symbolize_keys
end
public_url(style = default_style) click to toggle source
# File lib/paperclip/storage/fog.rb, line 145
def public_url(style = default_style)
  if @options[:fog_host]
    "#{dynamic_fog_host_for_style(style)}/#{path(style)}"
  else
    if fog_credentials[:provider] == "AWS"
      "#{scheme}://#{host_name_for_directory}/#{path(style)}"
    else
      directory.files.new(key: path(style)).public_url
    end
  end
end

Private Instance Methods

connection() click to toggle source
# File lib/paperclip/storage/fog.rb, line 231
def connection
  @connection ||= ::Fog::Storage.new(fog_credentials)
end
convert_time(time) click to toggle source
# File lib/paperclip/storage/fog.rb, line 193
def convert_time(time)
  time = Time.now + time if time.is_a?(Integer)
  time
end
directory() click to toggle source
# File lib/paperclip/storage/fog.rb, line 235
def directory
  @directory ||= connection.directories.new(key: directory_name)
end
directory_name() click to toggle source
# File lib/paperclip/storage/fog.rb, line 239
def directory_name
  if @options[:fog_directory].respond_to?(:call)
    @options[:fog_directory].call(self)
  else
    @options[:fog_directory]
  end
end
dynamic_fog_host_for_style(style) click to toggle source
# File lib/paperclip/storage/fog.rb, line 198
def dynamic_fog_host_for_style(style)
  if @options[:fog_host].respond_to?(:call)
    @options[:fog_host].call(self)
  else
    @options[:fog_host] =~ /%d/ ? @options[:fog_host] % (path(style).hash % 4) : @options[:fog_host]
  end
end
find_credentials(creds) click to toggle source
# File lib/paperclip/storage/fog.rb, line 214
def find_credentials(creds)
  case creds
  when File
    YAML::safe_load(ERB.new(File.read(creds.path)).result)
  when String, Pathname
    YAML::safe_load(ERB.new(File.read(creds)).result)
  when Hash
    creds
  else
    if creds.respond_to?(:call)
      creds.call(self)
    else
      raise ArgumentError, "Credentials are not a path, file, hash or proc."
    end
  end
end
host_name_for_directory() click to toggle source
# File lib/paperclip/storage/fog.rb, line 206
def host_name_for_directory
  if directory_name.to_s =~ Fog::AWS_BUCKET_SUBDOMAIN_RESTRICTON_REGEX
    "#{directory_name}.s3.amazonaws.com"
  else
    "s3.amazonaws.com/#{directory_name}"
  end
end
scheme() click to toggle source
# File lib/paperclip/storage/fog.rb, line 247
def scheme
  @scheme ||= fog_credentials[:scheme] || "https"
end