Class: Shrine::Storage::FileSystem

Inherits:
Object
  • Object
show all
Defined in:
lib/shrine/storage/file_system.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(directory, prefix: nil, clean: true, permissions: 0644, directory_permissions: 0755) ⇒ FileSystem

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.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 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

Instance Attribute Details

#directoryObject (readonly)

Returns the value of attribute directory.



9
10
11
# File 'lib/shrine/storage/file_system.rb', line 9

def directory
  @directory
end

#directory_permissionsObject (readonly)

Returns the value of attribute directory_permissions.



9
10
11
# File 'lib/shrine/storage/file_system.rb', line 9

def directory_permissions
  @directory_permissions
end

#permissionsObject (readonly)

Returns the value of attribute permissions.



9
10
11
# File 'lib/shrine/storage/file_system.rb', line 9

def permissions
  @permissions
end

#prefixObject (readonly)

Returns the value of attribute prefix.



9
10
11
# File 'lib/shrine/storage/file_system.rb', line 9

def prefix
  @prefix
end

Instance Method Details

#clear!(&condition) ⇒ Object

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


104
105
106
107
108
109
110
111
112
113
114
# 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) ⇒ Object

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



85
86
87
88
89
90
# 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) ⇒ Object

Deletes the specified directory on the filesystem.

file_system.delete_prefixed("somekey/derivatives/")


95
96
97
# File 'lib/shrine/storage/file_system.rb', line 95

def delete_prefixed(delete_prefix)
  FileUtils.rm_rf directory.join(delete_prefix)
end

#exists?(id) ⇒ Boolean

Returns true if the file exists on the filesystem.

Returns:

  • (Boolean)


69
70
71
# File 'lib/shrine/storage/file_system.rb', line 69

def exists?(id)
  path(id).exist?
end

#open(id) ⇒ Object

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



62
63
64
65
66
# File 'lib/shrine/storage/file_system.rb', line 62

def open(id, **)
  path(id).open(binmode: true, **)
rescue Errno::ENOENT
  raise Shrine::FileNotFound, "file #{id.inspect} not found on storage"
end

#path(id) ⇒ Object

Returns the full path to the file. Raises Shrine::Error if the id would resolve to a location outside of the storage #directory (e.g. an id containing ../ path traversal sequences in attacker-controlled data).



119
120
121
122
123
124
125
126
127
128
# File 'lib/shrine/storage/file_system.rb', line 119

def path(id)
  path = directory.join(id.gsub("/", File::SEPARATOR))
  expanded = path.expand_path

  unless expanded == directory || expanded.to_s.start_with?("#{directory}#{File::SEPARATOR}")
    raise Shrine::Error, "path #{id.inspect} resolves outside of the storage directory"
  end

  path
end

#upload(io, id, move: false) ⇒ Object

Copies the file into the given location.



50
51
52
53
54
55
56
57
58
# 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) ⇒ Object

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.



78
79
80
81
# File 'lib/shrine/storage/file_system.rb', line 78

def url(id, host: nil, **)
  path = (prefix ? relative_path(id) : path(id)).to_s
  host ? host + path : path
end