Module: Refile

Defined in:
lib/refile.rb,
lib/refile/app.rb,
lib/refile/type.rb,
lib/refile/file.rb,
lib/refile/rails.rb,
lib/refile/version.rb,
lib/refile/attacher.rb,
lib/refile/signature.rb,
lib/refile/backend/s3.rb,
lib/refile/attachment.rb,
lib/refile/custom_logger.rb,
lib/refile/random_hasher.rb,
lib/refile/backend_macros.rb,
lib/refile/image_processing.rb,
lib/refile/backend/file_system.rb,
lib/refile/rails/attachment_helper.rb,
lib/refile/attachment/active_record.rb

Defined Under Namespace

Modules: ActiveRecord, Attachment, AttachmentHelper, Backend Classes: App, File, ImageProcessor, RandomHasher, Signature, Type

Constant Summary collapse

VERSION =
"0.5.3"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.allow_originString

Value for Access-Control-Allow-Origin header

Returns:

  • (String)

55
56
57
# File 'lib/refile.rb', line 55

def allow_origin
  @allow_origin
end

.appRefile::App?

A shortcut to the instance of the Rack application. This should be set when the application is initialized. refile/rails sets this value.

Returns:


28
29
30
# File 'lib/refile.rb', line 28

def app
  @app
end

.automountBoolean

Should the rack application be automounted in a Rails app?

If set to false then Refile.app should be mounted in the Rails application routes.rb with the options at: Refile.mount_point, as: :refile_app

The default is true.

Returns:

  • (Boolean)

75
76
77
# File 'lib/refile.rb', line 75

def automount
  @automount
end

.content_max_ageInteger

Value for Cache-Control: max-age= header

Returns:

  • (Integer)

60
61
62
# File 'lib/refile.rb', line 60

def content_max_age
  @content_max_age
end

.direct_uploadArray[String]

A list of names which identify backends in the global backend registry. The Rack application allows POST requests to only the backends specified in this config option. This defaults to ["cache"], only allowing direct uploads to the cache backend.

Returns:

  • (Array[String])

45
46
47
# File 'lib/refile.rb', line 45

def direct_upload
  @direct_upload
end

.hostString?

The host name that the Rack application can be reached at. If not set, Refile will use an absolute URL without hostname. It is strongly recommended to run Refile behind a CDN and to set this to the hostname of the CDN distribution. A protocol relative URL is recommended for this value.

Returns:

  • (String, nil)

37
38
39
# File 'lib/refile.rb', line 37

def host
  @host
end

.loggerLogger

Logger that should be used by rack application

Returns:

  • (Logger)

50
51
52
# File 'lib/refile.rb', line 50

def logger
  @logger
end

.mount_pointString

Where should the rack application be mounted? The default is 'attachments'.

Returns:

  • (String)

65
66
67
# File 'lib/refile.rb', line 65

def mount_point
  @mount_point
end

.secret_keyString

Value for generating signed attachment urls to protect from DoS

Returns:

  • (String)

80
81
82
# File 'lib/refile.rb', line 80

def secret_key
  @secret_key
end

Class Method Details

.attachment_url(object, name, *args, prefix: Refile.mount_point, filename: nil, format: nil, host: Refile.host) ⇒ String?

Generate a URL to an attachment. This method receives an instance of a class which has used the Refile::Attachment#attachment macro to generate an attachment column, and the name of this column, and based on this generates a URL to a App.

Optionally the name of a processor and arguments to it can be appended.

If the filename option is not given, the filename is taken from the metadata stored in the attachment, or eventually falls back to the name.

The host defaults to host, which is useful for serving all attachments from a CDN. You can also override the host via the host option.

Returns nil if there is no file attached.

Examples:

attachment_url(@post, :document)

With processor

attachment_url(@post, :image, :fill, 300, 300, format: "jpg")

Parameters:

  • object (Refile::Attachment)

    Instance of a class which has an attached file

  • name (Symbol)

    The name of the attachment column

  • filename (String, nil) (defaults to: nil)

    The filename to be appended to the URL

  • format (String, nil) (defaults to: nil)

    A file extension to be appended to the URL

  • host (String, nil) (defaults to: Refile.host)

    Override the host

  • prefix (String, nil) (defaults to: Refile.mount_point)

    Adds a prefix to the URL if the application is not mounted at root

Returns:

  • (String, nil)

    The generated URL


238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/refile.rb', line 238

def attachment_url(object, name, *args, prefix: Refile.mount_point, filename: nil, format: nil, host: Refile.host)
  attacher = object.send(:"#{name}_attacher")
  file = attacher.get
  return unless file

  filename ||= attacher.basename || name.to_s
  format ||= attacher.extension

  backend_name = Refile.backends.key(file.backend)

  filename = Rack::Utils.escape(filename)
  filename << "." << format.to_s if format

  uri = URI(host.to_s)
  base_path = ::File.join("", backend_name, *args.map(&:to_s), file.id.to_s, filename)
  uri.path = ::File.join("", *prefix, token(base_path), base_path)

  uri.to_s
end

.backendsHash{String => Backend}

A global registry of backends.

Returns:


85
86
87
# File 'lib/refile.rb', line 85

def backends
  @backends ||= {}
end

.cacheBackend

A shortcut to retrieving the backend named "cache" from the global registry.

Returns:


158
159
160
# File 'lib/refile.rb', line 158

def cache
  backends["cache"]
end

.cache=(backend) ⇒ Object

A shortcut to setting the backend named "cache" in the global registry.

Parameters:


165
166
167
# File 'lib/refile.rb', line 165

def cache=(backend)
  backends["cache"] = backend
end

.configure { ... } ⇒ Object

Yield the Refile module as a convenience for configuring multiple config options at once.

Yields:

  • Refile


173
174
175
# File 'lib/refile.rb', line 173

def configure
  yield self
end

.extract_content_type(uploadable) ⇒ String?

Extract the content type from an uploadable object. If the content type cannot be determined, this method will return nil.

Parameters:

  • uploadable (IO)

    The uploadable object to extract the content type from

Returns:

  • (String, nil)

    The extracted content type


196
197
198
199
200
201
202
203
204
205
206
# File 'lib/refile.rb', line 196

def extract_content_type(uploadable)
  if uploadable.respond_to?(:content_type)
    uploadable.content_type
  else
    filename = extract_filename(uploadable)
    if filename
      content_type = MIME::Types.of(filename).first
      content_type.to_s if content_type
    end
  end
end

.extract_filename(uploadable) ⇒ String?

Extract the filename from an uploadable object. If the filename cannot be determined, this method will return nil.

Parameters:

  • uploadable (IO)

    The uploadable object to extract the filename from

Returns:

  • (String, nil)

    The extracted filename


182
183
184
185
186
187
188
189
# File 'lib/refile.rb', line 182

def extract_filename(uploadable)
  path = if uploadable.respond_to?(:original_filename)
    uploadable.original_filename
  elsif uploadable.respond_to?(:path)
    uploadable.path
  end
  ::File.basename(path) if path
end

.processor(name, processor = nil) {|Refile::File| ... }

This method returns an undefined value.

Adds a processor. The processor must respond to call, both receiving and returning an IO-like object. Alternatively a block can be given to this method which also receives and returns an IO-like object.

An IO-like object is recommended to be an instance of the IO class or one of its subclasses, like File or a StringIO, or a Refile::File. It can also be any other object which responds to size, read, eof? and close and mimics the behaviour of IO objects for these methods.

Examples:

With processor class

class Reverse
  def call(file)
    StringIO.new(file.read.reverse)
  en
end
Refile.processor(:reverse, Reverse)

With block

Refile.processor(:reverse) do |file|
  StringIO.new(file.read.reverse)
end

Parameters:

  • name (#to_s)

    The name of the processor

  • processor (Proc, nil) (defaults to: nil)

    The processor, must respond to call and.

Yields:

Yield Returns:

  • (IO)

    An IO-like object representing the processed file


134
135
136
137
# File 'lib/refile.rb', line 134

def processor(name, processor = nil, &block)
  processor ||= block
  processors[name.to_s] = processor
end

.processorsHash{String => Proc}

A global registry of processors. These will be used by the Rack application to manipulate files prior to serving them up to the user, based on options sent trough the URL. This can be used for example to resize images or to convert files to another file format.

Returns:

  • (Hash{String => Proc})

95
96
97
# File 'lib/refile.rb', line 95

def processors
  @processors ||= {}
end

.storeBackend

A shortcut to retrieving the backend named "store" from the global registry.

Returns:


143
144
145
# File 'lib/refile.rb', line 143

def store
  backends["store"]
end

.store=(backend) ⇒ Object

A shortcut to setting the backend named "store" in the global registry.

Parameters:


150
151
152
# File 'lib/refile.rb', line 150

def store=(backend)
  backends["store"] = backend
end

.token(path) ⇒ String?

Generate a signature for a given path concatenated with the configured secret token.

Raises an error if no secret token is configured.

Examples:

Refile.token('/store/f5f2e4/document.pdf')

Parameters:

  • path (String)

    The path to generate a token for

Returns:

  • (String, nil)

    The generated token

Raises:


268
269
270
271
272
273
274
275
276
277
278
# File 'lib/refile.rb', line 268

def token(path)
  if secret_key.nil?
    error = "Refile.secret_key was not set.\n\n"
    error << "Please add the following to your Refile configuration and restart your application:\n\n"
    error << "```\nRefile.secret_key = '#{SecureRandom.hex(64)}'\n```\n\n"

    raise error
  end

  OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new("sha1"), secret_key, path)
end

.typesHash{Symbol => Refile::Type}

A global registry of types. Currently, types are simply aliases for a set of content types, but their functionality may expand in the future.

Returns:


103
104
105
# File 'lib/refile.rb', line 103

def types
  @types ||= {}
end

.valid_token?(path, token) ⇒ Boolean

Check if the given token is a valid token for the given path.

Examples:

Refile.valid_token?('/store/f5f2e4/document.pdf', 'abcd1234')

Parameters:

  • path (String)

    The path to check validity for

  • token (String)

    The token to check

Returns:

  • (Boolean)

    Whether the token is valid

Raises:


289
290
291
292
293
294
# File 'lib/refile.rb', line 289

def valid_token?(path, token)
  expected = Digest::SHA1.hexdigest(token(path))
  actual = Digest::SHA1.hexdigest(token)

  expected == actual
end