echo_uploads 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/echo_uploads/file.rb +44 -16
- data/lib/echo_uploads/filesystem_store.rb +21 -17
- data/lib/echo_uploads/mapped_file.rb +5 -0
- data/lib/echo_uploads/mapper.rb +35 -0
- data/lib/echo_uploads/model.rb +83 -34
- data/lib/echo_uploads/perm_file_saving.rb +65 -19
- data/lib/echo_uploads/railtie.rb +4 -1
- data/lib/echo_uploads/s3_store.rb +51 -0
- data/lib/echo_uploads/temp_file_saving.rb +26 -5
- data/lib/echo_uploads.rb +4 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9302fa84aaf621556620c40904c1c8ead227b53d
|
4
|
+
data.tar.gz: 8ffbf38511536c4fee0a341c19f8a30424d3f54f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b53ba87f3dd560c8b163e2a8aba350f520eb982675a7c8629977816e473a80ea1b1d321dabc1716dade423ea20abaae833265f03b72f90be8966bc5a484ad2cc
|
7
|
+
data.tar.gz: 6110cf77bc31bc2906bb89c24fd493792ce84926ec44dc966f989cee08019a541f821ba6f937d12de731a12e2c580335a7d5af6e33728986603225e62b662b56
|
data/lib/echo_uploads/file.rb
CHANGED
@@ -9,11 +9,22 @@ module EchoUploads
|
|
9
9
|
|
10
10
|
before_destroy :delete_file_conditionally
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
attr_accessor :file
|
13
|
+
|
14
|
+
def compute_mime!(options)
|
15
|
+
if file and file.is_a?(::EchoUploads::MappedFile)
|
16
|
+
name = file.mapped_filename
|
17
|
+
else
|
18
|
+
name = original_filename
|
19
|
+
end
|
20
|
+
type = MIME::Types.type_for(name).first
|
14
21
|
self.mime_type = type ? type.content_type : 'application/octet-stream'
|
15
22
|
end
|
16
23
|
|
24
|
+
def compute_key!(file, options)
|
25
|
+
self.key = options[:key].call file
|
26
|
+
end
|
27
|
+
|
17
28
|
# Returns a proc that takes as its only argument an ActionDispatch::UploadedFile
|
18
29
|
# and returns a key string.
|
19
30
|
def self.default_key_proc
|
@@ -39,30 +50,47 @@ module EchoUploads
|
|
39
50
|
original_basename + original_extension
|
40
51
|
end
|
41
52
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
53
|
+
def path
|
54
|
+
storage.path key
|
55
|
+
end
|
56
|
+
|
57
|
+
# Pass in an attribute name, an ActionDispatch::Http::UploadedFile, and an options hash.
|
58
|
+
# Must set #file attribute first.
|
59
|
+
def persist!(attr, options)
|
60
|
+
unless(
|
61
|
+
file.is_a?(ActionDispatch::Http::UploadedFile) or
|
62
|
+
file.is_a?(Rack::Test::UploadedFile)
|
63
|
+
)
|
64
|
+
raise(
|
65
|
+
"Expected #file to be a ActionDispatch::Http::UploadedFile "+
|
66
|
+
"or Rack::Test::UploadedFile, but was #{file.inspect}"
|
67
|
+
)
|
68
|
+
end
|
46
69
|
|
47
70
|
# Configure and save the metadata object.
|
48
|
-
|
71
|
+
compute_key! file, options
|
49
72
|
self.owner_attr = attr
|
50
73
|
self.original_extension = ::File.extname(file.original_filename)
|
51
74
|
self.original_basename = ::File.basename(file.original_filename, original_extension)
|
52
|
-
compute_mime!
|
53
|
-
|
75
|
+
compute_mime! options
|
76
|
+
if options[:storage].is_a? String
|
77
|
+
self.storage_type = options[:storage]
|
78
|
+
else
|
79
|
+
self.storage_type = options[:storage].name
|
80
|
+
end
|
54
81
|
save!
|
55
82
|
|
56
83
|
# Write the file to the filestore.
|
57
|
-
|
58
|
-
|
59
|
-
storage.write key, file_to_write.tempfile
|
84
|
+
if file.is_a?(ActionDispatch::Http::UploadedFile)
|
85
|
+
storage.write key, file.tempfile
|
60
86
|
else
|
61
|
-
storage.write key,
|
87
|
+
storage.write key, file
|
62
88
|
end
|
63
|
-
|
64
|
-
|
65
|
-
|
89
|
+
|
90
|
+
# If we mapped the files, they were temporarily written to tmp/echo_uploads.
|
91
|
+
# Delete them.
|
92
|
+
if file.is_a?(::EchoUploads::MappedFile)
|
93
|
+
::File.delete file.path
|
66
94
|
end
|
67
95
|
|
68
96
|
# Prune any expired temporary files. (Unless automatic pruning was turned off in
|
@@ -1,5 +1,26 @@
|
|
1
1
|
module EchoUploads
|
2
2
|
class FilesystemStore < ::EchoUploads::AbstractStore
|
3
|
+
def delete(key)
|
4
|
+
_path = path(key)
|
5
|
+
::File.delete(_path) if ::File.exists?(_path)
|
6
|
+
end
|
7
|
+
|
8
|
+
def exists?(key)
|
9
|
+
::File.exists? path(key)
|
10
|
+
end
|
11
|
+
|
12
|
+
def open(key)
|
13
|
+
::File.open(path(key), 'rb', &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def path(key)
|
17
|
+
::File.join folder, key
|
18
|
+
end
|
19
|
+
|
20
|
+
def read(key)
|
21
|
+
File.read path(key)
|
22
|
+
end
|
23
|
+
|
3
24
|
def write(key, file)
|
4
25
|
_path = path key
|
5
26
|
unless ::File.exists?(_path)
|
@@ -14,23 +35,6 @@ module EchoUploads
|
|
14
35
|
end
|
15
36
|
end
|
16
37
|
|
17
|
-
def read(key)
|
18
|
-
File.read path(key)
|
19
|
-
end
|
20
|
-
|
21
|
-
def delete(key)
|
22
|
-
_path = path(key)
|
23
|
-
::File.delete(_path) if ::File.exists?(_path)
|
24
|
-
end
|
25
|
-
|
26
|
-
def open(key)
|
27
|
-
::File.open(path(key), 'rb', &block)
|
28
|
-
end
|
29
|
-
|
30
|
-
def path(key)
|
31
|
-
::File.join folder, key
|
32
|
-
end
|
33
|
-
|
34
38
|
private
|
35
39
|
|
36
40
|
# Can be customized in your per-environment config like this:
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module EchoUploads
|
4
|
+
class Mapper
|
5
|
+
def initialize(file)
|
6
|
+
unless(
|
7
|
+
file.is_a?(ActionDispatch::Http::UploadedFile) or
|
8
|
+
file.is_a?(Rack::Test::UploadedFile)
|
9
|
+
)
|
10
|
+
raise(
|
11
|
+
"Expected file to be a ActionDispatch::Http::UploadedFile "+
|
12
|
+
"or Rack::Test::UploadedFile, but was #{file.inspect}"
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
@uploaded_file = file
|
17
|
+
@outputs = []
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :outputs
|
21
|
+
|
22
|
+
def write(ext)
|
23
|
+
folder = ::File.join Rails.root, 'tmp/echo_uploads'
|
24
|
+
FileUtils.mkdir_p folder
|
25
|
+
path = ::File.join(folder, SecureRandom.hex(15) + ext)
|
26
|
+
yield path
|
27
|
+
file = ::File.open path, 'rb'
|
28
|
+
mapped_file = ::EchoUploads::MappedFile.new(
|
29
|
+
tempfile: file, filename: @uploaded_file.original_filename
|
30
|
+
)
|
31
|
+
mapped_file.mapped_filename = ::File.basename path
|
32
|
+
outputs << mapped_file
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/echo_uploads/model.rb
CHANGED
@@ -19,9 +19,11 @@ module EchoUploads
|
|
19
19
|
|
20
20
|
def echo_uploads_data
|
21
21
|
Base64.encode64(JSON.dump(self.class.echo_uploads_config.inject({}) do |hash, (attr, cfg)|
|
22
|
-
|
23
|
-
if
|
24
|
-
hash[attr] =
|
22
|
+
metas = send("#{attr}_tmp_metadata")
|
23
|
+
if metas
|
24
|
+
hash[attr] = metas.map do |meta|
|
25
|
+
{'id' => meta.id, 'key' => meta.key}
|
26
|
+
end
|
25
27
|
end
|
26
28
|
hash
|
27
29
|
end)).strip
|
@@ -30,17 +32,35 @@ module EchoUploads
|
|
30
32
|
# Pass in a hash that's been encoded as JSON and then Base64.
|
31
33
|
def echo_uploads_data=(data)
|
32
34
|
parsed = JSON.parse Base64.decode64(data)
|
35
|
+
# parsed will look like:
|
36
|
+
# { 'attr1' => [ {'id' => 1, 'key' => 'abc...'} ] }
|
37
|
+
unless parsed.is_a? Hash
|
38
|
+
raise ArgumentError, "Invalid JSON structure in: #{parsed.inspect}"
|
39
|
+
end
|
33
40
|
parsed.each do |attr, attr_data|
|
34
|
-
#
|
35
|
-
#
|
36
|
-
|
37
|
-
|
41
|
+
# If the :map option was passed, there may be multiple variants of the uploaded
|
42
|
+
# file. Even if not, attr_data is still a one-element array.
|
43
|
+
unless attr_data.is_a? Array
|
44
|
+
raise ArgumentError, "Invalid JSON structure in: #{parsed.inspect}"
|
45
|
+
end
|
46
|
+
attr_data.each do |variant_data|
|
47
|
+
unless variant_data.is_a? Hash
|
48
|
+
raise ArgumentError, "Invalid JSON structure in: #{parsed.inspect}"
|
49
|
+
end
|
50
|
+
if meta = ::EchoUploads::File.where(
|
51
|
+
id: variant_data['id'], key: variant_data['key'], temporary: true
|
52
|
+
).first
|
53
|
+
if send("#{attr}_tmp_metadata").nil?
|
54
|
+
send "#{attr}_tmp_metadata=", []
|
55
|
+
end
|
56
|
+
send("#{attr}_tmp_metadata") << meta
|
57
|
+
end
|
38
58
|
end
|
39
59
|
end
|
40
60
|
end
|
41
61
|
|
42
62
|
# Helper method used internally Echo Uploads.
|
43
|
-
def
|
63
|
+
def echo_uploads_map_metadata(attr, options)
|
44
64
|
meta = send("#{attr}_metadata")
|
45
65
|
meta ? yield(meta) : nil
|
46
66
|
end
|
@@ -54,16 +74,26 @@ module EchoUploads
|
|
54
74
|
# - +expires+: Length of time temporary files will be persisted. Defaults to
|
55
75
|
# +1.day+.
|
56
76
|
# - +storage+: A class that persists uploaded files to disk, to the cloud, or to
|
57
|
-
# wherever else you want. Defaults to +
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
77
|
+
# wherever else you want. Defaults to +Rails.configuration.echo_uploads.storage+,
|
78
|
+
# which in turn is +EchoUploads::FilesystemStore+ by default.
|
79
|
+
# - +map+: A Proc that accepts an ActionDispatch::Htttp::UploadedFile and an
|
80
|
+
# instance of +EchoUploads::Mapper+. It should transform the file data (e.g.
|
81
|
+
# scaling an image). It should then write the transformed data to one of more
|
82
|
+
# temporary files. To get the temporary file path(s), call +#write+ on the
|
83
|
+
# +Mapper+. See readme.md for an example. The +:map+ option can also accept a
|
84
|
+
# symbol naming an an instance method that works the same way as the previously
|
85
|
+
# described Proc.
|
86
|
+
# - +multiple+: You use the +:map+ option to write multiple versions of the file.
|
87
|
+
# E.g. multiple thumbnail sizes. If you do so, you must pass +multiple: true+.
|
88
|
+
# This will make the association with +EchoUploads::File+ a +has_many+ instead of
|
89
|
+
# a +has_one+. The first file you write in the map function becomes the default.
|
90
|
+
# E.g.: Your model is called +Widget+, and the upload file attribute is called
|
91
|
+
# +photo+. You pass +:map+ with a method that writes three files. If you call
|
92
|
+
# +Widget#photo_path+, it will return the path to the first of the three files.
|
63
93
|
def echo_upload(attr, options = {})
|
64
94
|
options = {
|
65
95
|
expires: 1.day,
|
66
|
-
storage:
|
96
|
+
storage: Rails.configuration.echo_uploads.storage,
|
67
97
|
key: ::EchoUploads::File.default_key_proc
|
68
98
|
}.merge(options)
|
69
99
|
|
@@ -80,43 +110,45 @@ module EchoUploads
|
|
80
110
|
# Define the writer method for the file attribute.
|
81
111
|
define_method("#{attr}=") do |file|
|
82
112
|
if options[:map]
|
83
|
-
|
113
|
+
mapper = ::EchoUploads::Mapper.new file
|
84
114
|
if options[:map].is_a? Proc
|
85
|
-
options[:map].call file,
|
115
|
+
options[:map].call file, mapper
|
86
116
|
else
|
87
|
-
send(options[:map], file,
|
117
|
+
send(options[:map], file, mapper)
|
88
118
|
end
|
89
|
-
|
90
|
-
|
119
|
+
# Write an array of ActionDispatch::Http::UploadedFile objects to the instance
|
120
|
+
# variable.
|
121
|
+
send "mapped_#{attr}=", mapper.outputs
|
91
122
|
end
|
92
123
|
instance_variable_set "@#{attr}", file
|
93
124
|
end
|
94
125
|
|
95
|
-
# Define the accessor methods for the mapped version of the file.
|
126
|
+
# Define the accessor methods for the mapped version(s) of the file. Returns
|
127
|
+
# an array.
|
96
128
|
attr_accessor "mapped_#{attr}"
|
97
129
|
|
130
|
+
# Define the original filename method.
|
131
|
+
define_method("#{attr}_original_filename") do
|
132
|
+
echo_uploads_map_metadata(attr, options, &:original_filename)
|
133
|
+
end
|
134
|
+
|
98
135
|
# Define the path method. This method will raise if the given storage
|
99
136
|
# class doesn't support the #path method.
|
100
137
|
define_method("#{attr}_path") do
|
101
|
-
|
102
|
-
meta.
|
138
|
+
echo_uploads_map_metadata(attr, options) do |meta|
|
139
|
+
meta.path
|
103
140
|
end
|
104
141
|
end
|
105
142
|
|
106
143
|
# Define the MIME type method.
|
107
144
|
define_method("#{attr}_mime") do
|
108
|
-
|
145
|
+
echo_uploads_map_metadata(attr, options, &:mime_type)
|
109
146
|
end
|
110
147
|
alias_method "#{attr}_mime_type", "#{attr}_mime"
|
111
148
|
|
112
|
-
# Define the original filename method.
|
113
|
-
define_method("#{attr}_original_filename") do
|
114
|
-
map_metadata(attr, &:original_filename)
|
115
|
-
end
|
116
|
-
|
117
149
|
# Define the key method
|
118
150
|
define_method("#{attr}_key") do
|
119
|
-
|
151
|
+
echo_uploads_map_metadata(attr, options, &:key)
|
120
152
|
end
|
121
153
|
|
122
154
|
# Define the has_x? method. Returns true if a permanent or temporary file has been
|
@@ -147,10 +179,27 @@ module EchoUploads
|
|
147
179
|
end
|
148
180
|
|
149
181
|
# Define the association with the metadata model.
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
182
|
+
if options[:multiple]
|
183
|
+
has_many("#{attr}_metadatas".to_sym,
|
184
|
+
->() { where(owner_attr: attr) },
|
185
|
+
as: :owner, dependent: :destroy, class_name: '::EchoUploads::File'
|
186
|
+
)
|
187
|
+
|
188
|
+
alias_method attr.to_s.pluralize, "#{attr}_metadatas"
|
189
|
+
|
190
|
+
define_method("#{attr}_metadata") do
|
191
|
+
send("#{attr}_metadatas").first
|
192
|
+
end
|
193
|
+
|
194
|
+
define_method("#{attr}_metadata=") do |val|
|
195
|
+
send("#{attr}_metadatas") << val
|
196
|
+
end
|
197
|
+
else
|
198
|
+
has_one("#{attr}_metadata".to_sym,
|
199
|
+
->() { where(owner_attr: attr) },
|
200
|
+
as: :owner, dependent: :destroy, class_name: '::EchoUploads::File'
|
201
|
+
)
|
202
|
+
end
|
154
203
|
|
155
204
|
# Define the temp attribute for the metadata model.
|
156
205
|
attr_accessor "#{attr}_tmp_metadata"
|
@@ -10,34 +10,80 @@ module EchoUploads
|
|
10
10
|
after_save do |model|
|
11
11
|
if (file = send(attr)).present?
|
12
12
|
# A file is being uploaded during this request cycle.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# references it.
|
17
|
-
meta.delete_file_conditionally
|
13
|
+
|
14
|
+
if options[:multiple]
|
15
|
+
metas = send("#{attr}_metadatas")
|
18
16
|
else
|
19
|
-
|
20
|
-
meta = ::EchoUploads::File.new(owner: model, temporary: false)
|
21
|
-
send("#{attr}_metadata=", meta)
|
17
|
+
metas = [send("#{attr}_metadata")].compact
|
22
18
|
end
|
23
|
-
|
24
|
-
|
19
|
+
|
20
|
+
# metas is now an array of ::EchoUploads::File instances. The array may
|
21
|
+
# be empty.
|
22
|
+
|
23
|
+
if metas.any?
|
24
|
+
# Previous permanent file(s) exist. This is a new version being uploaded.
|
25
|
+
# Delete the old version(s).
|
26
|
+
metas.each(&:destroy)
|
27
|
+
end
|
28
|
+
|
29
|
+
# No previous permanent files exists. The metas array is currently empty or
|
30
|
+
# else contains deleted records. We need to rebuild that array by constructing
|
31
|
+
# (but not yet saving) new EchoUploads::File objects.
|
32
|
+
|
33
|
+
if options[:multiple]
|
34
|
+
mapped_files = send("mapped_#{attr}") ||
|
35
|
+
raise('echo_uploads called with :multiple, but :map option was missing')
|
36
|
+
metas = mapped_files.map do |mapped_file|
|
37
|
+
::EchoUploads::File.new(
|
38
|
+
owner: model, temporary: false, file: mapped_file
|
39
|
+
)
|
40
|
+
end
|
41
|
+
send("#{attr}_metadatas=", metas)
|
42
|
+
else
|
43
|
+
metas = [::EchoUploads::File.new(
|
44
|
+
owner: model, temporary: false, file: send(attr)
|
45
|
+
)]
|
46
|
+
send("#{attr}_metadata=", metas.first)
|
47
|
+
end
|
48
|
+
|
49
|
+
# metas is still an array of the EchoUploads::File instances. If the array was
|
50
|
+
# initially empty (meaning no previous permanent file existed), then it has
|
51
|
+
# since been populated.
|
52
|
+
|
53
|
+
metas.each do |meta|
|
54
|
+
meta.persist! attr, options
|
55
|
+
end
|
56
|
+
elsif metas = send("#{attr}_tmp_metadata")
|
25
57
|
# A file has not been uploaded during this request cycle. However, the
|
26
58
|
# submitted form "remembered" a temporary metadata record that was previously
|
27
|
-
# saved.
|
28
|
-
|
29
|
-
#
|
59
|
+
# saved.
|
60
|
+
|
61
|
+
# Delete any existing metadata record. (It's possible we
|
30
62
|
# were trying to replace an old version of the file, and there were validation
|
31
63
|
# errors on the first attempt.)
|
32
|
-
|
64
|
+
|
65
|
+
if options[:multiple]
|
66
|
+
model.send("#{attr}_metadatas").each(&:destroy)
|
67
|
+
elsif old = model.send("#{attr}_metadata")
|
33
68
|
old.destroy
|
34
69
|
end
|
35
70
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
meta
|
71
|
+
# We need not call persist! here, because the file is already persisted. (Nor
|
72
|
+
# could we call it, because persist! requires an
|
73
|
+
# ActionDispatch::HTTP::UploadedFile.) Mark the metadata record as permanent
|
74
|
+
# and set its owner.
|
75
|
+
metas.each do |meta|
|
76
|
+
meta.owner = model
|
77
|
+
meta.temporary = false
|
78
|
+
meta.expires_at = nil
|
79
|
+
meta.save!
|
80
|
+
end
|
81
|
+
|
82
|
+
if options[:multiple]
|
83
|
+
send("#{attr}_metadatas=", metas)
|
84
|
+
else
|
85
|
+
send("#{attr}_metadata=", metas.first)
|
86
|
+
end
|
41
87
|
end
|
42
88
|
end
|
43
89
|
end
|
data/lib/echo_uploads/railtie.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Uses the official Amazon Web Services SDK gem:
|
2
|
+
# gem install aws-sdk
|
3
|
+
module EchoUploads
|
4
|
+
class S3Store < ::EchoUploads::AbstractStore
|
5
|
+
def delete(key)
|
6
|
+
bucket.objects[key].delete
|
7
|
+
end
|
8
|
+
|
9
|
+
def exists?(key)
|
10
|
+
bucket.objects[key].exists?
|
11
|
+
end
|
12
|
+
|
13
|
+
def read(key)
|
14
|
+
data = ''
|
15
|
+
bucket.objects[key].read { |chunk| data << chunk }
|
16
|
+
data
|
17
|
+
end
|
18
|
+
|
19
|
+
def url(key, options = {})
|
20
|
+
options = {method: :read}.merge(options)
|
21
|
+
bucket.objects[key].url_for options.delete(:method), options
|
22
|
+
end
|
23
|
+
|
24
|
+
def write(key, file)
|
25
|
+
bucket.objects[key].write file
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def bucket
|
31
|
+
if Rails.configuration.echo_uploads.aws
|
32
|
+
s3 = AWS::S3.new Rails.configuration.echo_uploads.aws
|
33
|
+
else
|
34
|
+
s3 = AWS::S3.new
|
35
|
+
end
|
36
|
+
bucket_name = Rails.configuration.echo_uploads.s3.bucket || raise(
|
37
|
+
'You must define config.echo_uploads.s3.bucket in your application config.'
|
38
|
+
)
|
39
|
+
if s3.buckets[bucket_name].nil?
|
40
|
+
s3.buckets.create bucket_name
|
41
|
+
end
|
42
|
+
s3.buckets[bucket_name]
|
43
|
+
end
|
44
|
+
|
45
|
+
def folder
|
46
|
+
Rails.configuration.echo_uploads.s3.folder || raise(
|
47
|
+
'You must define config.echo_uploads.s3.folder in your application config.'
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -28,11 +28,32 @@ module EchoUploads
|
|
28
28
|
# That's fine. We'll now have a permanent and a temporary one. The temporary
|
29
29
|
# one will replace the permanent one if and when the user resubmits with
|
30
30
|
# valid data.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
|
32
|
+
# Construct an array of EchoUploads::File instances. The array might have only
|
33
|
+
# one element.
|
34
|
+
if options[:multiple]
|
35
|
+
mapped_files = send("mapped_#{attr}") ||
|
36
|
+
raise('echo_uploads called with :multiple, but :map option was missing')
|
37
|
+
metas = mapped_files.map do |mapped_file|
|
38
|
+
::EchoUploads::File.new(
|
39
|
+
owner: nil, temporary: true, expires_at: options[:expires].from_now,
|
40
|
+
file: mapped_file
|
41
|
+
)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
metas = [::EchoUploads::File.new(
|
45
|
+
owner: nil, temporary: true, expires_at: options[:expires].from_now,
|
46
|
+
file: send(attr)
|
47
|
+
)]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Persist each file. (There might only be one, though.)
|
51
|
+
metas.each do |meta|
|
52
|
+
meta.persist! attr, options
|
53
|
+
end
|
54
|
+
|
55
|
+
# Set the attr_tmp_metadata attribute so the form can remember our records.
|
56
|
+
send("#{attr}_tmp_metadata=", metas)
|
36
57
|
end
|
37
58
|
end
|
38
59
|
|
data/lib/echo_uploads.rb
CHANGED
@@ -6,5 +6,8 @@ require 'echo_uploads/perm_file_saving'
|
|
6
6
|
require 'echo_uploads/temp_file_saving'
|
7
7
|
require 'echo_uploads/model'
|
8
8
|
require 'echo_uploads/file'
|
9
|
+
require 'echo_uploads/mapper'
|
10
|
+
require 'echo_uploads/mapped_file'
|
9
11
|
require 'echo_uploads/abstract_store'
|
10
|
-
require 'echo_uploads/filesystem_store'
|
12
|
+
require 'echo_uploads/filesystem_store'
|
13
|
+
require 'echo_uploads/s3_store'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: echo_uploads
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jarrett Colby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mime-types
|
@@ -38,7 +38,9 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
description: '
|
41
|
+
description: Gracefully handles invalid form submissions, so users don't have to resubmit
|
42
|
+
the file. Supports transforming the file before saving, e.g. scaling an image. Compatible
|
43
|
+
with any storage mechanism, including the local filesystem and the cloud.
|
42
44
|
email: jarrett@madebyhq.com
|
43
45
|
executables: []
|
44
46
|
extensions: []
|
@@ -48,9 +50,12 @@ files:
|
|
48
50
|
- lib/echo_uploads/abstract_store.rb
|
49
51
|
- lib/echo_uploads/file.rb
|
50
52
|
- lib/echo_uploads/filesystem_store.rb
|
53
|
+
- lib/echo_uploads/mapped_file.rb
|
54
|
+
- lib/echo_uploads/mapper.rb
|
51
55
|
- lib/echo_uploads/model.rb
|
52
56
|
- lib/echo_uploads/perm_file_saving.rb
|
53
57
|
- lib/echo_uploads/railtie.rb
|
58
|
+
- lib/echo_uploads/s3_store.rb
|
54
59
|
- lib/echo_uploads/temp_file_saving.rb
|
55
60
|
- lib/echo_uploads/validation.rb
|
56
61
|
homepage: https://github.com/jarrett/echo_uploads
|