module Shrine::InstanceMethods
Attributes
The symbol identifier for the storage used by the uploader.
Public Class Methods
Accepts a storage symbol registered in ‘Shrine.storages`.
Shrine.new(:store)
# File lib/shrine.rb, line 184 def initialize(storage_key) @storage_key = storage_key.to_sym storage # ensure storage is registered end
Public Instance Methods
Extracts filename, size and MIME type from the file, which is later accessible through UploadedFile#metadata
.
# File lib/shrine.rb, line 228 def extract_metadata(io, **options) { "filename" => extract_filename(io), "size" => extract_size(io), "mime_type" => extract_mime_type(io), } end
Generates a unique location for the uploaded file, preserving the file extension. Can be overriden in uploaders for generating custom location.
# File lib/shrine.rb, line 222 def generate_location(io, metadata: {}, **options) basic_location(io, metadata: metadata) end
The class-level options hash. This should probably not be modified at the instance level.
# File lib/shrine.rb, line 238 def opts self.class.opts end
Returns the storage object referenced by the identifier.
# File lib/shrine.rb, line 191 def storage self.class.find_storage(storage_key) end
The main method for uploading files. Takes an IO-like object and an optional context hash (used internally by Shrine::Attacher
). It calls user-defined process, and afterwards it calls store. The ‘io` is closed after upload.
uploader.upload(io) uploader.upload(io, metadata: { "foo" => "bar" }) # add metadata uploader.upload(io, location: "path/to/file") # specify location uploader.upload(io, upload_options: { acl: "public-read" }) # add upload options
# File lib/shrine.rb, line 204 def upload(io, **options) _enforce_io(io) metadata = get_metadata(io, **options) location = get_location(io, **options, metadata: metadata) _upload(io, **options, location: location, metadata: metadata) self.class::UploadedFile.new( id: location, storage: storage_key, metadata: metadata, ) end
Private Instance Methods
Asserts that the object is a valid IO object, specifically that it responds to ‘#read`, `#eof?`, `#rewind`, `#size` and `#close`. If the object doesn’t respond to one of these methods, a Shrine::InvalidFile
error is raised.
# File lib/shrine.rb, line 308 def _enforce_io(io) missing_methods = %i[read eof? rewind close].select { |m| !io.respond_to?(m) } raise InvalidFile.new(io, missing_methods) if missing_methods.any? end
# File lib/shrine.rb, line 244 def _upload(io, location:, metadata:, upload_options: {}, close: true, delete: false, **) storage.upload(io, location, shrine_metadata: metadata, **upload_options) ensure io.close if close File.unlink(io.path) if delete && io.respond_to?(:path) && File.exist?(io.path) end
Generates a basic location for an uploaded file
# File lib/shrine.rb, line 274 def basic_location(io, metadata:) extension = ".#{io.extension}" if io.is_a?(UploadedFile) && io.extension extension ||= File.extname(metadata["filename"].to_s).downcase basename = generate_uid(io) basename + extension end
Attempts to extract the appropriate filename from the IO object.
# File lib/shrine.rb, line 252 def extract_filename(io) if io.respond_to?(:original_filename) io.original_filename elsif io.respond_to?(:path) && io.path File.basename(io.path) end end
Attempts to extract the MIME type from the IO object.
# File lib/shrine.rb, line 261 def extract_mime_type(io) if io.respond_to?(:content_type) && io.content_type Shrine.warn "The \"mime_type\" Shrine metadata field will be set from the \"Content-Type\" request header, which might not hold the actual MIME type of the file. It is recommended to load the determine_mime_type plugin which determines MIME type from file content." io.content_type.split(";").first # exclude media type parameters end end
Extracts the filesize from the IO object.
# File lib/shrine.rb, line 269 def extract_size(io) io.size if io.respond_to?(:size) end
Generates a unique identifier that can be used for a location.
# File lib/shrine.rb, line 314 def generate_uid(io) SecureRandom.hex end
Retrieves the location for the given IO and context. First it looks for the ‘:location` option, otherwise it calls generate_location
.
# File lib/shrine.rb, line 299 def get_location(io, location: nil, **options) location ||= generate_location(io, **options) location or fail Error, "location generated for #{io.inspect} was nil" end
If the IO object is a Shrine::UploadedFile
, it simply copies over its metadata, otherwise it calls extract_metadata
.
# File lib/shrine.rb, line 284 def get_metadata(io, metadata: nil, **options) if io.is_a?(UploadedFile) && metadata != true result = io.metadata.dup elsif metadata != false result = extract_metadata(io, **options) else result = {} end result = result.merge(metadata) if metadata.is_a?(Hash) result end