class Shrine::Storage::FileSystem

Attributes

directory[R]
directory_permissions[R]
permissions[R]
prefix[R]

Public Class Methods

new(directory, prefix: nil, clean: true, permissions: 0644, directory_permissions: 0755) click to toggle source

Initializes a storage for uploading to the filesystem.

:prefix : The directory relative to ‘directory` to which files will be stored,

and it is included in the URL.

:permissions : The UNIX permissions applied to created files. Can be set to ‘nil`,

in which case the default permissions will be applied. Defaults to
`0644`.

:directory_permissions : The UNIX permissions applied to created directories. Can be set to

`nil`, in which case the default permissions will be applied. Defaults
to `0755`.

:clean : By default empty folders inside the directory are automatically

deleted, but if it happens that it causes too much load on the
filesystem, you can set this option to `false`.
# File lib/shrine/storage/file_system.rb, line 31
def initialize(directory, prefix: nil, clean: true, permissions: 0644, directory_permissions: 0755)
  if prefix
    @prefix = Pathname(relative(prefix))
    @directory = Pathname(directory).join(@prefix).expand_path
  else
    @directory = Pathname(directory).expand_path
  end

  @permissions = permissions
  @directory_permissions = directory_permissions
  @clean = clean

  unless @directory.exist?
    @directory.mkpath
    @directory.chmod(directory_permissions) if directory_permissions
  end
end

Public Instance Methods

clear!(&condition) click to toggle source

Deletes all files from the directory. If a block is passed in, deletes only the files for which the block evaluates to true.

file_system.clear! # deletes all files and subdirectories in the storage directory
file_system.clear! { |path| path.mtime < Time.now - 7*24*60*60 } # deletes only files older than 1 week
# File lib/shrine/storage/file_system.rb, line 104
def clear!(&condition)
  if condition
    list_files(directory) do |path|
      next unless condition.call(path)
      path.delete
      clean(path) if clean?
    end
  else
    directory.children.each(&:rmtree)
  end
end
delete(id) click to toggle source

Delets the file, and by default deletes the containing directory if it’s empty.

# File lib/shrine/storage/file_system.rb, line 85
def delete(id)
  path = path(id)
  path.delete
  clean(path) if clean?
rescue Errno::ENOENT
end
delete_prefixed(delete_prefix) click to toggle source

Deletes the specified directory on the filesystem.

file_system.delete_prefixed("somekey/derivatives/")
# File lib/shrine/storage/file_system.rb, line 95
def delete_prefixed(delete_prefix)
  FileUtils.rm_rf directory.join(delete_prefix)
end
exists?(id) click to toggle source

Returns true if the file exists on the filesystem.

# File lib/shrine/storage/file_system.rb, line 69
def exists?(id)
  path(id).exist?
end
open(id, **options) click to toggle source

Opens the file on the given location in read mode. Accepts additional ‘File.open` arguments.

# File lib/shrine/storage/file_system.rb, line 62
def open(id, **options)
  path(id).open(binmode: true, **options)
rescue Errno::ENOENT
  raise Shrine::FileNotFound, "file #{id.inspect} not found on storage"
end
path(id) click to toggle source

Returns the full path to the file.

# File lib/shrine/storage/file_system.rb, line 117
def path(id)
  directory.join(id.gsub("/", File::SEPARATOR))
end
upload(io, id, move: false, **) click to toggle source

Copies the file into the given location.

# File lib/shrine/storage/file_system.rb, line 50
def upload(io, id, move: false, **)
  if move && movable?(io)
    move(io, path!(id))
  else
    IO.copy_stream(io, path!(id))
  end

  path(id).chmod(permissions) if permissions
end
url(id, host: nil, **options) click to toggle source

If prefix is not present, returns a path composed of directory and the given ‘id`. If prefix is present, it excludes the directory part from the returned path (e.g. directory can be set to “public” folder). Both cases accept a `:host` value which will be prefixed to the generated path.

# File lib/shrine/storage/file_system.rb, line 78
def url(id, host: nil, **options)
  path = (prefix ? relative_path(id) : path(id)).to_s
  host ? host + path : path
end

Protected Instance Methods

clean(path) click to toggle source

Cleans all empty subdirectories up the hierarchy.

# File lib/shrine/storage/file_system.rb, line 124
def clean(path)
  path.dirname.ascend do |pathname|
    if dir_empty?(pathname) && pathname != directory
      pathname.rmdir
    else
      break
    end
  end
end
clean?() click to toggle source
# File lib/shrine/storage/file_system.rb, line 134
def clean?
  @clean
end

Private Instance Methods

dir_empty?(path) click to toggle source
# File lib/shrine/storage/file_system.rb, line 180
def dir_empty?(path)
  Dir.empty?(path)
end
list_files(directory) { |path| ... } click to toggle source
# File lib/shrine/storage/file_system.rb, line 173
def list_files(directory)
  Pathname("#{directory}/") # add trailing slash to make it work with symlinks
    .find
    .each { |path| yield path if path.file? }
end
movable?(io) click to toggle source

Returns true if the file is a ‘File` or a UploadedFile uploaded by the FileSystem storage.

# File lib/shrine/storage/file_system.rb, line 153
def movable?(io)
  io.respond_to?(:path) ||
    (io.is_a?(UploadedFile) && io.storage.is_a?(Storage::FileSystem))
end
move(io, path) click to toggle source

Moves the file to the given location. This gets called by the ‘moving` plugin.

# File lib/shrine/storage/file_system.rb, line 142
def move(io, path)
  if io.respond_to?(:path)
    FileUtils.mv io.path, path
  else
    FileUtils.mv io.storage.path(io.id), path
    io.storage.clean(io.storage.path(io.id)) if io.storage.clean?
  end
end
path!(id) click to toggle source

Creates all intermediate directories for that location.

# File lib/shrine/storage/file_system.rb, line 159
def path!(id)
  path = path(id)
  FileUtils.mkdir_p(path.dirname, mode: directory_permissions)
  path
end
relative(path) click to toggle source
# File lib/shrine/storage/file_system.rb, line 169
def relative(path)
  path.sub(%r{^/}, "")
end
relative_path(id) click to toggle source
# File lib/shrine/storage/file_system.rb, line 165
def relative_path(id)
  "/" + prefix.join(id.gsub("/", File::SEPARATOR)).to_s
end