-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
store.rb
142 lines (128 loc) · 4.15 KB
/
store.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
module CarrierWave
module Uploader
module Store
extend ActiveSupport::Concern
include CarrierWave::Uploader::Callbacks
include CarrierWave::Uploader::Configuration
include CarrierWave::Uploader::Cache
included do
prepend Module.new {
def initialize(*)
super
@file, @filename, @cache_id, @identifier, @deduplication_index = nil
end
}
end
##
# Override this in your Uploader to change the filename.
#
# Be careful using record ids as filenames. If the filename is stored in the database
# the record id will be nil when the filename is set. Don't use record ids unless you
# understand this limitation.
#
# Do not use the version_name in the filename, as it will prevent versions from being
# loaded correctly.
#
# === Returns
#
# [String] a filename
#
def filename
@filename
end
##
# Returns a filename which doesn't conflict with already-stored files.
#
# === Returns
#
# [String] the filename with suffix added for deduplication
#
def deduplicated_filename
return unless filename
return filename unless @deduplication_index
parts = filename.split('.')
basename = parts.shift
basename.sub!(/ ?\(\d+\)\z/, '')
([basename.to_s + (@deduplication_index > 1 ? "(#{@deduplication_index})" : '')] + parts).join('.')
end
##
# Calculates the path where the file should be stored. If +for_file+ is given, it will be
# used as the identifier, otherwise +CarrierWave::Uploader#identifier+ is assumed.
#
# === Parameters
#
# [for_file (String)] name of the file <optional>
#
# === Returns
#
# [String] the store path
#
def store_path(for_file=identifier)
File.join([store_dir, full_filename(for_file)].compact)
end
##
# Stores the file by passing it to this Uploader's storage engine.
#
# If new_file is omitted, a previously cached file will be stored.
#
# === Parameters
#
# [new_file (File, IOString, Tempfile)] any kind of file object
#
def store!(new_file=nil)
cache!(new_file) if new_file && !cached?
if !cache_only && @file && @cache_id
with_callbacks(:store, new_file) do
new_file = storage.store!(@file)
if delete_tmp_file_after_storage
@file.delete unless move_to_store
cache_storage.delete_dir!(cache_path(nil))
end
@file = new_file
@identifier = storage.identifier
@original_filename = @cache_id = @deduplication_index = nil
@staged = false
end
end
end
##
# Retrieves the file from the storage.
#
# === Parameters
#
# [identifier (String)] uniquely identifies the file to retrieve
#
def retrieve_from_store!(identifier)
with_callbacks(:retrieve_from_store, identifier) do
@file = storage.retrieve!(identifier)
@identifier = identifier
end
end
##
# Look for an identifier which doesn't collide with the given already-stored identifiers.
# It is done by adding a index number as the suffix.
# For example, if there's 'image.jpg' and the @deduplication_index is set to 2,
# The stored file will be named as 'image(2).jpg'.
#
# === Parameters
#
# [current_identifiers (Array[String])] List of identifiers for already-stored files
#
def deduplicate(current_identifiers)
@deduplication_index = nil
return unless current_identifiers.include?(identifier)
(1..current_identifiers.size + 1).each do |i|
@deduplication_index = i
break unless current_identifiers.include?(identifier)
end
end
private
def full_filename(for_file)
forcing_extension(for_file)
end
def storage
@storage ||= self.class.storage.new(self)
end
end # Store
end # Uploader
end # CarrierWave