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
  begin
    require 'fog'
  rescue LoadError => e
    e.message << " (You may need to install the fog gem)"
    raise e
  end unless defined?(Fog)

  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
    Paperclip.interpolates(:fog_public_url) do |attachment, style|
      attachment.public_url(style)
    end unless Paperclip::Interpolations.respond_to? :fog_public_url
  end
end

Public Instance Methods

copy_to_local_file(style, local_dest_path) click to toggle source
# File lib/paperclip/storage/fog.rb, line 173
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 63
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 152
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

  return expiring_url
end
flush_deletes() click to toggle source
# File lib/paperclip/storage/fog.rb, line 132
def flush_deletes
  for path in @queued_for_delete do
    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 103
def flush_writes
  for style, file in @queued_for_write do
    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 71
def fog_credentials
  @fog_credentials ||= parse_credentials(@options[:fog_credentials])
end
fog_file() click to toggle source
# File lib/paperclip/storage/fog.rb, line 75
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 88
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 168
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 140
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 227
def connection
  @connection ||= ::Fog::Storage.new(fog_credentials)
end
convert_time(time) click to toggle source
# File lib/paperclip/storage/fog.rb, line 187
def convert_time(time)
  if time.is_a?(Integer)
    time = Time.now + time
  end
  time
end
directory() click to toggle source
# File lib/paperclip/storage/fog.rb, line 231
def directory
  @directory ||= connection.directories.new(key: directory_name)
end
directory_name() click to toggle source
# File lib/paperclip/storage/fog.rb, line 235
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 194
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 210
def find_credentials(creds)
  case creds
  when File
    YAML::load(ERB.new(File.read(creds.path)).result)
  when String, Pathname
    YAML::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 202
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 243
def scheme
  @scheme ||= fog_credentials[:scheme] || 'https'
end