jnicklas-carrierwave 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Generators +4 -0
- data/LICENSE +20 -0
- data/README.md +211 -0
- data/Rakefile +96 -0
- data/TODO +0 -0
- data/lib/carrierwave/mount.rb +93 -0
- data/lib/carrierwave/orm/activerecord.rb +20 -0
- data/lib/carrierwave/orm/datamapper.rb +20 -0
- data/lib/carrierwave/processing/image_science.rb +70 -0
- data/lib/carrierwave/processing/rmagick.rb +161 -0
- data/lib/carrierwave/sanitized_file.rb +231 -0
- data/lib/carrierwave/storage/abstract.rb +80 -0
- data/lib/carrierwave/storage/file.rb +40 -0
- data/lib/carrierwave/storage/s3.rb +83 -0
- data/lib/carrierwave/uploader.rb +420 -0
- data/lib/carrierwave.rb +63 -0
- data/lib/generators/templates/uploader.rbt +32 -0
- data/lib/generators/uploader_generator.rb +20 -0
- data/spec/fixtures/bork.txt +1 -0
- data/spec/fixtures/test.jpeg +1 -0
- data/spec/fixtures/test.jpg +1 -0
- data/spec/mount_spec.rb +180 -0
- data/spec/orm/activerecord_spec.rb +168 -0
- data/spec/orm/datamapper_spec.rb +133 -0
- data/spec/sanitized_file_spec.rb +618 -0
- data/spec/spec_helper.rb +122 -0
- data/spec/uploader_spec.rb +709 -0
- metadata +89 -0
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'rmagick'
|
2
|
+
|
3
|
+
module CarrierWave
|
4
|
+
|
5
|
+
##
|
6
|
+
# This module simplifies manipulation with RMagick by providing a set
|
7
|
+
# of convenient helper methods. If you want to use them, you'll need to
|
8
|
+
# require this file
|
9
|
+
#
|
10
|
+
# require 'carrierwave/processing/rmagick'
|
11
|
+
#
|
12
|
+
# And then include it in your uploader
|
13
|
+
#
|
14
|
+
# MyUploade < CarrierWave::Uploader
|
15
|
+
# include CarrierWave::RMagick
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# You can now use the provided helpers:
|
19
|
+
#
|
20
|
+
# MyUploade < CarrierWave::Uploader
|
21
|
+
# include CarrierWave::RMagick
|
22
|
+
#
|
23
|
+
# process :resize_to_fit => [200, 200]
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# Or create your own helpers with the powerful manipulate! method. Check
|
27
|
+
# out the RMagick docs at http://www.imagemagick.org/RMagick/doc/ for more
|
28
|
+
# info
|
29
|
+
#
|
30
|
+
# MyUploade < CarrierWave::Uploader
|
31
|
+
# include CarrierWave::RMagick
|
32
|
+
#
|
33
|
+
# process :do_stuff => 10.0
|
34
|
+
#
|
35
|
+
# def do_stuff(blur_factor)
|
36
|
+
# manipulate! do |img|
|
37
|
+
# img = img.sepiatone
|
38
|
+
# img = img.auto_orient
|
39
|
+
# img = img.radial_blur(blur_factor)
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
module RMagick
|
45
|
+
|
46
|
+
##
|
47
|
+
# Changes the image encoding format to the given format
|
48
|
+
#
|
49
|
+
# @see http://www.imagemagick.org/RMagick/doc/magick.html#formats
|
50
|
+
# @param [#to_s] format an abreviation of the format
|
51
|
+
# @yieldparam [Magick::Image] img additional manipulations to perform
|
52
|
+
# @example
|
53
|
+
# image.convert(:png)
|
54
|
+
#
|
55
|
+
def convert(format)
|
56
|
+
manipulate! do |img|
|
57
|
+
img.format = format.to_s.upcase
|
58
|
+
img = yield(img) if block_given?
|
59
|
+
img
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# From the RMagick documentation: "Resize the image to fit within the
|
65
|
+
# specified dimensions while retaining the original aspect ratio. The
|
66
|
+
# image may be shorter or narrower than specified in the smaller dimension
|
67
|
+
# but will not be larger than the specified values."
|
68
|
+
#
|
69
|
+
# @see http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fit
|
70
|
+
#
|
71
|
+
# @param [Integer] width the width to scale the image to
|
72
|
+
# @param [Integer] height the height to scale the image to
|
73
|
+
# @yieldparam [Magick::Image] img additional manipulations to perform
|
74
|
+
#
|
75
|
+
def resize_to_fit(width, height)
|
76
|
+
manipulate! do |img|
|
77
|
+
img.resize_to_fit!(width, height)
|
78
|
+
img = yield(img) if block_given?
|
79
|
+
img
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
alias_method :resize, :resize_to_fit
|
84
|
+
|
85
|
+
##
|
86
|
+
# From the RMagick documentation: "Resize the image to fit within the
|
87
|
+
# specified dimensions while retaining the aspect ratio of the original
|
88
|
+
# image. If necessary, crop the image in the larger dimension."
|
89
|
+
#
|
90
|
+
# @see http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fill
|
91
|
+
#
|
92
|
+
# @param [Integer] width the width to scale the image to
|
93
|
+
# @param [Integer] height the height to scale the image to
|
94
|
+
# @yieldparam [Magick::Image] img additional manipulations to perform
|
95
|
+
#
|
96
|
+
def resize_to_fill(width, height)
|
97
|
+
manipulate! do |img|
|
98
|
+
img.resize_to_fill!(width, height)
|
99
|
+
img = yield(img) if block_given?
|
100
|
+
img
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
alias_method :crop_resized, :resize_to_fill
|
105
|
+
|
106
|
+
##
|
107
|
+
# Resize the image to fit within the specified dimensions while retaining
|
108
|
+
# the original aspect ratio. If necessary will pad the remaining area
|
109
|
+
# with the given color, which defaults to transparent (for gif and png,
|
110
|
+
# white for jpeg).
|
111
|
+
#
|
112
|
+
# @param [Integer] width the width to scale the image to
|
113
|
+
# @param [Integer] height the height to scale the image to
|
114
|
+
# @param [String, :transparent] background the color of the background as a hexcode, like "#ff45de"
|
115
|
+
# @param [Magick::GravityType] gravity how to position the image
|
116
|
+
# @yieldparam [Magick::Image] img additional manipulations to perform
|
117
|
+
#
|
118
|
+
def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
|
119
|
+
manipulate! do |img|
|
120
|
+
img.resize_to_fit!(width, height)
|
121
|
+
new_img = ::Magick::Image.new(width, height)
|
122
|
+
if background == :transparent
|
123
|
+
new_img = new_img.matte_floodfill(1, 1)
|
124
|
+
else
|
125
|
+
new_img = new_img.color_floodfill(1, 1, ::Magick::Pixel.from_color(background))
|
126
|
+
end
|
127
|
+
new_img = new_img.composite(img, gravity, ::Magick::OverCompositeOp)
|
128
|
+
new_img = yield(new_img) if block_given?
|
129
|
+
new_img
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Manipulate the image with RMagick. This method will load up an image
|
135
|
+
# and then pass each of its frames to the supplied block. It will then
|
136
|
+
# save the image to disk.
|
137
|
+
#
|
138
|
+
# Note: This method assumes that the object responds to current_path
|
139
|
+
# any class that this is mixed into must have a current_path method.
|
140
|
+
#
|
141
|
+
# @yieldparam [Magick::Image] img manipulations to perform
|
142
|
+
# @raise [CarrierWave::ProcessingError] if manipulation failed.
|
143
|
+
#
|
144
|
+
def manipulate!
|
145
|
+
image = ::Magick::Image.read(current_path)
|
146
|
+
|
147
|
+
if image.size > 1
|
148
|
+
list = ::Magick::ImageList.new
|
149
|
+
image.each do |frame|
|
150
|
+
list << yield( frame )
|
151
|
+
end
|
152
|
+
list.write(current_path)
|
153
|
+
else
|
154
|
+
yield( image.first ).write(current_path)
|
155
|
+
end
|
156
|
+
rescue ::Magick::ImageMagickError => e
|
157
|
+
raise CarrierWave::ProcessingError.new("Failed to manipulate with rmagick, maybe it is not an image? Original Error: #{e}")
|
158
|
+
end
|
159
|
+
|
160
|
+
end # RMagick
|
161
|
+
end # CarrierWave
|
@@ -0,0 +1,231 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
class SanitizedFile
|
3
|
+
|
4
|
+
attr_accessor :file, :options
|
5
|
+
|
6
|
+
def initialize(file, options = {})
|
7
|
+
self.file = file
|
8
|
+
self.options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Returns the filename as is, without sanizting it.
|
13
|
+
#
|
14
|
+
# @return [String] the unsanitized filename
|
15
|
+
#
|
16
|
+
def original_filename
|
17
|
+
return @original_filename if @original_filename
|
18
|
+
if @file and @file.respond_to?(:original_filename)
|
19
|
+
@file.original_filename
|
20
|
+
elsif path
|
21
|
+
File.basename(path)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Returns the filename, sanitized to strip out any evil characters.
|
27
|
+
#
|
28
|
+
# @return [String] the sanitized filename
|
29
|
+
#
|
30
|
+
def filename
|
31
|
+
sanitize(original_filename) if original_filename
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :identifier, :filename
|
35
|
+
|
36
|
+
##
|
37
|
+
# Returns the part of the filename before the extension. So if a file is called 'test.jpeg'
|
38
|
+
# this would return 'test'
|
39
|
+
#
|
40
|
+
# @return [String] the first part of the filename
|
41
|
+
#
|
42
|
+
def basename
|
43
|
+
split_extension(filename)[0] if filename
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Returns the file extension
|
48
|
+
#
|
49
|
+
# @return [String] the extension
|
50
|
+
#
|
51
|
+
def extension
|
52
|
+
split_extension(filename)[1] if filename
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Returns the file's size.
|
57
|
+
#
|
58
|
+
# @return [Integer] the file's size in bytes.
|
59
|
+
#
|
60
|
+
def size
|
61
|
+
if @file.respond_to?(:size)
|
62
|
+
@file.size
|
63
|
+
elsif path
|
64
|
+
File.size(path)
|
65
|
+
else
|
66
|
+
0
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Returns the full path to the file. If the file has no path, it will return nil.
|
72
|
+
#
|
73
|
+
# @return [String, nil] the path where the file is located.
|
74
|
+
#
|
75
|
+
def path
|
76
|
+
unless @file.blank?
|
77
|
+
if string?
|
78
|
+
File.expand_path(@file)
|
79
|
+
elsif @file.respond_to?(:path) and not @file.path.blank?
|
80
|
+
File.expand_path(@file.path)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Returns true if the file is supplied as a pathname or as a string.
|
87
|
+
#
|
88
|
+
# @return [Boolean]
|
89
|
+
#
|
90
|
+
def string?
|
91
|
+
!!((@file.is_a?(String) || @file.is_a?(Pathname)) && !@file.blank?)
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Checks if the file is valid and has a non-zero size
|
96
|
+
#
|
97
|
+
# @return [Boolean]
|
98
|
+
#
|
99
|
+
def empty?
|
100
|
+
(@file.nil? && @path.nil?) || self.size.nil? || self.size.zero?
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Checks if the file exists
|
105
|
+
#
|
106
|
+
# @return [Boolean]
|
107
|
+
#
|
108
|
+
def exists?
|
109
|
+
return File.exists?(self.path) if self.path
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Returns the contents of the file.
|
115
|
+
#
|
116
|
+
# @return [String] contents of the file
|
117
|
+
#
|
118
|
+
def read
|
119
|
+
if string?
|
120
|
+
File.read(@file)
|
121
|
+
else
|
122
|
+
@file.rewind if @file.respond_to?(:rewind)
|
123
|
+
@file.read
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# Moves the file to the given path
|
129
|
+
#
|
130
|
+
# @param [String] new_path The path where the file should be moved.
|
131
|
+
#
|
132
|
+
def move_to(new_path)
|
133
|
+
return if self.empty?
|
134
|
+
new_path = File.expand_path(new_path)
|
135
|
+
|
136
|
+
mkdir!(new_path)
|
137
|
+
if exists?
|
138
|
+
FileUtils.mv(path, new_path) unless new_path == path
|
139
|
+
else
|
140
|
+
File.open(new_path, "wb") { |f| f.write(read) }
|
141
|
+
end
|
142
|
+
chmod!(new_path)
|
143
|
+
self.file = new_path
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Creates a copy of this file and moves it to the given path. Returns the copy.
|
148
|
+
#
|
149
|
+
# @param [String] new_path The path where the file should be copied to.
|
150
|
+
# @return [CarrierWave::SanitizedFile] the location where the file will be stored.
|
151
|
+
#
|
152
|
+
def copy_to(new_path)
|
153
|
+
return if self.empty?
|
154
|
+
new_path = File.expand_path(new_path)
|
155
|
+
|
156
|
+
mkdir!(new_path)
|
157
|
+
if exists?
|
158
|
+
FileUtils.cp(path, new_path) unless new_path == path
|
159
|
+
else
|
160
|
+
File.open(new_path, "wb") { |f| f.write(read) }
|
161
|
+
end
|
162
|
+
chmod!(new_path)
|
163
|
+
self.class.new(new_path)
|
164
|
+
end
|
165
|
+
|
166
|
+
##
|
167
|
+
# Removes the file from the filesystem.
|
168
|
+
#
|
169
|
+
def delete
|
170
|
+
FileUtils.rm(self.path) if exists?
|
171
|
+
end
|
172
|
+
|
173
|
+
##
|
174
|
+
# Returns the content type of the file.
|
175
|
+
#
|
176
|
+
# @return [String] the content type of the file
|
177
|
+
#
|
178
|
+
def content_type
|
179
|
+
return @content_type if @content_type
|
180
|
+
@file.content_type.chomp if @file.respond_to?(:content_type) and @file.content_type
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def file=(file)
|
186
|
+
if file.is_a?(Hash)
|
187
|
+
@file = file["tempfile"]
|
188
|
+
@original_filename = file["filename"]
|
189
|
+
@content_type = file["content_type"]
|
190
|
+
else
|
191
|
+
@file = file
|
192
|
+
@original_filename = nil
|
193
|
+
@content_type = nil
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# create the directory if it doesn't exist
|
198
|
+
def mkdir!(path)
|
199
|
+
FileUtils.mkdir_p(File.dirname(path)) unless File.exists?(File.dirname(path))
|
200
|
+
end
|
201
|
+
|
202
|
+
def chmod!(path)
|
203
|
+
File.chmod(@options[:permissions], path) if @options[:permissions]
|
204
|
+
end
|
205
|
+
|
206
|
+
# Sanitize the filename, to prevent hacking
|
207
|
+
def sanitize(name)
|
208
|
+
name = name.gsub("\\", "/") # work-around for IE
|
209
|
+
name = File.basename(name)
|
210
|
+
name = name.gsub(/[^a-zA-Z0-9\.\-\+_]/,"_")
|
211
|
+
name = "_#{name}" if name =~ /^\.+$/
|
212
|
+
name = "unnamed" if name.size == 0
|
213
|
+
return name.downcase
|
214
|
+
end
|
215
|
+
|
216
|
+
def split_extension(fn)
|
217
|
+
# regular expressions to try for identifying extensions
|
218
|
+
ext_regexps = [
|
219
|
+
/^(.+)\.([^\.]{1,3}\.[^\.]{1,4})$/, # matches "something.tar.gz"
|
220
|
+
/^(.+)\.([^\.]+)$/ # matches "something.jpg"
|
221
|
+
]
|
222
|
+
ext_regexps.each do |regexp|
|
223
|
+
if fn =~ regexp
|
224
|
+
return $1, $2
|
225
|
+
end
|
226
|
+
end
|
227
|
+
return fn, "" # In case we weren't able to split the extension
|
228
|
+
end
|
229
|
+
|
230
|
+
end # SanitizedFile
|
231
|
+
end # CarrierWave
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Storage
|
3
|
+
##
|
4
|
+
# This file serves mostly as a specification for Storage engines. There is no requirement
|
5
|
+
# that storage engines must be a subclass of this class. However, any storage engine must
|
6
|
+
# conform to the following interface:
|
7
|
+
#
|
8
|
+
# The storage engine must respond to store!, taking an uploader object and a
|
9
|
+
# CarrierWave::SanitizedFile as parameters. This method should do something to store
|
10
|
+
# the given file, and then return an object.
|
11
|
+
#
|
12
|
+
# The storage engine must respond to retrieve!, taking an uploader object and an identifier
|
13
|
+
# as parameters. This method should do retrieve and then return an object.
|
14
|
+
#
|
15
|
+
# The objects returned by store! and retrieve! both *must* respond to +identifier+, taking
|
16
|
+
# no arguments. Identifier is a string that uniquely identifies this file and can be used
|
17
|
+
# to retrieve it later.
|
18
|
+
#
|
19
|
+
class Abstract
|
20
|
+
|
21
|
+
##
|
22
|
+
# Do setup specific for this storage engine
|
23
|
+
#
|
24
|
+
def self.setup!; end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Do something to store the file
|
28
|
+
#
|
29
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
30
|
+
# @param [CarrierWave::SanitizedFile] file the file to store
|
31
|
+
#
|
32
|
+
# @return [#identifier] an object
|
33
|
+
#
|
34
|
+
def self.store!(uploader, file)
|
35
|
+
self.new
|
36
|
+
end
|
37
|
+
|
38
|
+
# Do something to retrieve the file
|
39
|
+
#
|
40
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
41
|
+
# @param [String] identifier uniquely identifies the file
|
42
|
+
#
|
43
|
+
# @return [#identifier] an object
|
44
|
+
#
|
45
|
+
def self.retrieve!(uploader, identifier)
|
46
|
+
self.new
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Should return a String that uniquely identifies this file and can be used to retrieve it from
|
51
|
+
# the same storage engine later on.
|
52
|
+
#
|
53
|
+
# This is OPTIONAL
|
54
|
+
#
|
55
|
+
# @return [String] path to the file
|
56
|
+
#
|
57
|
+
def identifier; end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Should return the url where the file is publically accessible. If this is not set, then
|
61
|
+
# it is assumed that the url is the path relative to the public directory.
|
62
|
+
#
|
63
|
+
# This is OPTIONAL
|
64
|
+
#
|
65
|
+
# @return [String] file's url
|
66
|
+
#
|
67
|
+
def url; end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Should return the path where the file is corrently located. This is OPTIONAL.
|
71
|
+
#
|
72
|
+
# This is OPTIONAL
|
73
|
+
#
|
74
|
+
# @return [String] path to the file
|
75
|
+
#
|
76
|
+
def path; end
|
77
|
+
|
78
|
+
end # Abstract
|
79
|
+
end # Storage
|
80
|
+
end # CarrierWave
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Storage
|
3
|
+
class File < Abstract
|
4
|
+
|
5
|
+
def initialize(uploader)
|
6
|
+
@uploader = uploader
|
7
|
+
end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Move the file to the uploader's store path.
|
11
|
+
#
|
12
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
13
|
+
# @param [CarrierWave::SanitizedFile] file the file to store
|
14
|
+
#
|
15
|
+
# @return [CarrierWave::SanitizedFile] a sanitized file
|
16
|
+
#
|
17
|
+
def self.store!(uploader, file)
|
18
|
+
path = ::File.join(uploader.store_dir, uploader.filename)
|
19
|
+
path = ::File.expand_path(path, uploader.root)
|
20
|
+
file.move_to(path)
|
21
|
+
file
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Retrieve the file from its store path
|
26
|
+
#
|
27
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
28
|
+
# @param [String] identifier the filename of the file
|
29
|
+
#
|
30
|
+
# @return [CarrierWave::SanitizedFile] a sanitized file
|
31
|
+
#
|
32
|
+
def self.retrieve!(uploader, identifier)
|
33
|
+
path = ::File.join(uploader.store_dir, identifier)
|
34
|
+
path = ::File.expand_path(path, uploader.root)
|
35
|
+
CarrierWave::SanitizedFile.new(path)
|
36
|
+
end
|
37
|
+
|
38
|
+
end # File
|
39
|
+
end # Storage
|
40
|
+
end # CarrierWave
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Storage
|
3
|
+
##
|
4
|
+
# Uploads things to Amazon S3 webservices
|
5
|
+
#
|
6
|
+
class S3 < Abstract
|
7
|
+
|
8
|
+
def initialize(bucket, store_dir, identifier)
|
9
|
+
@bucket = bucket
|
10
|
+
@store_dir = store_dir
|
11
|
+
@identifier = identifier
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Connect to Amazon S3
|
16
|
+
#
|
17
|
+
def self.setup!
|
18
|
+
require 'aws/s3'
|
19
|
+
AWS::S3::Base.establish_connection!(
|
20
|
+
:access_key_id => CarrierWave.config[:s3][:access_key_id],
|
21
|
+
:secret_access_key => CarrierWave.config[:s3][:secret_access_key]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# @return [String] the bucket set in the config options
|
27
|
+
#
|
28
|
+
def self.bucket
|
29
|
+
CarrierWave.config[:s3][:bucket]
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# @return [Symbol] the access priviliges the uploaded files should have
|
34
|
+
#
|
35
|
+
def self.access
|
36
|
+
CarrierWave.config[:s3][:access]
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Store the file on S3
|
41
|
+
#
|
42
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
43
|
+
# @param [CarrierWave::SanitizedFile] file the file to store
|
44
|
+
#
|
45
|
+
# @return [#identifier] an object
|
46
|
+
#
|
47
|
+
def self.store!(uploader, file)
|
48
|
+
AWS::S3::S3Object.store(::File.join(uploader.store_dir, uploader.filename), file.read, bucket, :access => access)
|
49
|
+
self.new(bucket, uploader.store_dir, uploader.filename)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Do something to retrieve the file
|
53
|
+
#
|
54
|
+
# @param [CarrierWave::Uploader] uploader an uploader object
|
55
|
+
# @param [String] identifier uniquely identifies the file
|
56
|
+
#
|
57
|
+
# @return [#identifier] an object
|
58
|
+
#
|
59
|
+
def self.retrieve!(uploader, identifier)
|
60
|
+
self.new(bucket, uploader.store_dir, identifier)
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Returns the filename on S3
|
65
|
+
#
|
66
|
+
# @return [String] path to the file
|
67
|
+
#
|
68
|
+
def identifier
|
69
|
+
@identifier
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Returns the url on Amazon's S3 service
|
74
|
+
#
|
75
|
+
# @return [String] file's url
|
76
|
+
#
|
77
|
+
def url
|
78
|
+
"http://s3.amazonaws.com/#{self.class.bucket}/#{@store_dir}/#{@identifier}"
|
79
|
+
end
|
80
|
+
|
81
|
+
end # S3
|
82
|
+
end # Storage
|
83
|
+
end # CarrierWave
|