attached 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +53 -0
- data/lib/attached.rb +189 -0
- data/lib/attached/attachment.rb +167 -0
- data/lib/attached/railtie.rb +12 -0
- data/lib/attached/storage.rb +25 -0
- data/lib/attached/storage/base.rb +72 -0
- data/lib/attached/storage/fs.rb +39 -0
- data/lib/attached/storage/s3.rb +77 -0
- metadata +86 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Kevin Sylvestre
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
= Attached
|
2
|
+
|
3
|
+
Attached is a Ruby on Rails file attachment tool that lets users upload to the cloud, then process in the cloud. The tool supports Amazon S3 by default. It surpasses Paperclip by providing built-in support for direct uploads to the cloud and by allowing integration with cloud based processing tools. However, in almost every other way Paperclip is better. The source code inspired (and copied) from Paperclip. If you aren't working in the cloud exclusively then this isn't for you!
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
gem install attached
|
8
|
+
|
9
|
+
== Examples
|
10
|
+
|
11
|
+
Migration:
|
12
|
+
|
13
|
+
class CreateVideo < ActiveRecord::Migration
|
14
|
+
def self.up
|
15
|
+
create_table :videos do |t|
|
16
|
+
t.string :video_extension
|
17
|
+
t.integer :video_size
|
18
|
+
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.down
|
24
|
+
drop_table :videos
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Model:
|
29
|
+
|
30
|
+
has_attached :video, :styles => {
|
31
|
+
:mp4_720p => { :extension => 'mp4' },
|
32
|
+
:mp4_480p => { :extension => 'mp4' },
|
33
|
+
:ogv_720p => { :extension => 'ogv' },
|
34
|
+
:ogv_480p => { :extension => 'ogv' },
|
35
|
+
}
|
36
|
+
|
37
|
+
Form:
|
38
|
+
|
39
|
+
<%= form_for @video, :html => { :multipart => true } do |form| %>
|
40
|
+
<%= form.file_field :video %>
|
41
|
+
<p class="errors"><%= @video.errors[:video] %></p>
|
42
|
+
<% end %>
|
43
|
+
|
44
|
+
View:
|
45
|
+
|
46
|
+
<video>
|
47
|
+
<source src="<%= @video.video.url(:mp4_480p) %>" />
|
48
|
+
<source src="<%= @video.video.url(:ogv_480p) %>" />
|
49
|
+
</video>
|
50
|
+
|
51
|
+
== Copyright
|
52
|
+
|
53
|
+
Copyright (c) 2010 Kevin Sylvestre. See LICENSE for details.
|
data/lib/attached.rb
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'attached/attachment'
|
2
|
+
require 'attached/railtie'
|
3
|
+
|
4
|
+
|
5
|
+
module Attached
|
6
|
+
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.extend ClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
|
16
|
+
# Initialize attached options used for communicating between class and instance methods.
|
17
|
+
|
18
|
+
def initialize_attached_options
|
19
|
+
write_inheritable_attribute(:attached_options, {})
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# Access attached options used for communicating between class and instance methods.
|
24
|
+
|
25
|
+
def attached_options
|
26
|
+
read_inheritable_attribute(:attached_options)
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# Add an attachment to a class.
|
31
|
+
#
|
32
|
+
# Options:
|
33
|
+
#
|
34
|
+
# * :styles -
|
35
|
+
# * :storage -
|
36
|
+
#
|
37
|
+
# Usage:
|
38
|
+
#
|
39
|
+
# has_attached :avatar
|
40
|
+
# has_attached :avatar, :storage => :s3
|
41
|
+
# has_attached :clip, styles => [ :mp4, :ogv ]
|
42
|
+
# has_attached :clip, styles => { :main => { :size => "480p", :format => "mp4" } }
|
43
|
+
|
44
|
+
def has_attached(name, options = {})
|
45
|
+
|
46
|
+
include InstanceMethods
|
47
|
+
|
48
|
+
initialize_attached_options unless attached_options
|
49
|
+
attached_options[name] = options
|
50
|
+
|
51
|
+
after_save :save_attached
|
52
|
+
after_destroy :destroy_attached
|
53
|
+
|
54
|
+
define_method name do
|
55
|
+
attachment_for(name)
|
56
|
+
end
|
57
|
+
|
58
|
+
define_method "#{name}=" do |file|
|
59
|
+
attachment_for(name).assign(file)
|
60
|
+
end
|
61
|
+
|
62
|
+
define_method "#{name}?" do
|
63
|
+
attachment_for(name).file?
|
64
|
+
end
|
65
|
+
|
66
|
+
after_validation do
|
67
|
+
|
68
|
+
self.errors[:"#{name}_size"].each do |message|
|
69
|
+
self.errors.add(name, message)
|
70
|
+
end
|
71
|
+
|
72
|
+
self.errors[:"#{name}_extension"].each do |message|
|
73
|
+
self.errors.add(name, message)
|
74
|
+
end
|
75
|
+
|
76
|
+
self.errors.delete(:"#{name}_size")
|
77
|
+
self.errors.delete(:"#{name}_extension")
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
# Validates an attached size in a specified range or minimum and maximum.
|
85
|
+
#
|
86
|
+
# Options:
|
87
|
+
#
|
88
|
+
# * :message - string to be displayed with :minimum and :maximum variables
|
89
|
+
# * :minimum - integer for the minimum byte size of the attached
|
90
|
+
# * :maximum - integer for the maximum byte size of teh attached
|
91
|
+
# * :in - range of bytes for file
|
92
|
+
#
|
93
|
+
# Usage:
|
94
|
+
#
|
95
|
+
# validates_attached_size :avatar, :range => 10.megabytes .. 20.megabytes
|
96
|
+
# validates_attached_size :avatar, :minimum => 10.megabytes, :maximum => 20.megabytes
|
97
|
+
# validates_attached_size :avatar, :message => "size must be between :minimum and :maximum bytes"
|
98
|
+
|
99
|
+
def validates_attached_size(name, options = {})
|
100
|
+
|
101
|
+
message = options[:message] || "size must be between :minimum and :maximum bytes"
|
102
|
+
|
103
|
+
minimum = options[:minimum] || options[:in] && options[:in].first || (0.0 / 1.0)
|
104
|
+
maximum = options[:maximum] || options[:in] && options[:in].last || (1.0 / 0.0)
|
105
|
+
|
106
|
+
range = minimum..maximum
|
107
|
+
|
108
|
+
message.gsub!(/:minimum/, minimum.to_s)
|
109
|
+
message.gsub!(/:maximum/, maximum.to_s)
|
110
|
+
|
111
|
+
validates_inclusion_of :"#{name}_size", :in => range, :message => message,
|
112
|
+
:if => options[:if], :unless => options[:unless]
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
# Validates that an attachment is included.
|
118
|
+
#
|
119
|
+
# Options:
|
120
|
+
#
|
121
|
+
# * :message - string to be displayed
|
122
|
+
#
|
123
|
+
# Usage:
|
124
|
+
#
|
125
|
+
# validates_attached_presence :avatar
|
126
|
+
# validates_attached_presence :avatar, :message => "must be attached"
|
127
|
+
|
128
|
+
def validates_attached_presence(name, options = {})
|
129
|
+
|
130
|
+
message = options[:message] || "must be attached"
|
131
|
+
|
132
|
+
validates_presence_of :"#{name}_extension", :message => message,
|
133
|
+
:if => options[:if], :unless => options[:unless]
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
module InstanceMethods
|
142
|
+
|
143
|
+
|
144
|
+
# Create or access attachment.
|
145
|
+
#
|
146
|
+
# Usage:
|
147
|
+
#
|
148
|
+
# attachment_for :avatar
|
149
|
+
|
150
|
+
def attachment_for(name)
|
151
|
+
@_attached_attachments ||= {}
|
152
|
+
@_attached_attachments[name] ||= Attachment.new(name, self, self.class.attached_options[name])
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
# Log and save all attached (using specified storage).
|
157
|
+
#
|
158
|
+
# Usage:
|
159
|
+
#
|
160
|
+
# before_save :save_attached
|
161
|
+
|
162
|
+
def save_attached
|
163
|
+
logger.info "[attached] save attached"
|
164
|
+
|
165
|
+
self.class.attached_options.each do |name, options|
|
166
|
+
attachment_for(name).save
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
# Log and destroy all attached (using specified storage).
|
172
|
+
#
|
173
|
+
# Usage:
|
174
|
+
#
|
175
|
+
# before_save :destroy_attached
|
176
|
+
|
177
|
+
def destroy_attached
|
178
|
+
logger.info "[attached] destroy attached"
|
179
|
+
|
180
|
+
self.class.attached_options.each do |name, options|
|
181
|
+
attachment_for(name).destroy
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'attached/storage'
|
2
|
+
|
3
|
+
module Attached
|
4
|
+
|
5
|
+
class Attachment
|
6
|
+
|
7
|
+
|
8
|
+
attr_reader :file
|
9
|
+
attr_reader :name
|
10
|
+
attr_reader :instance
|
11
|
+
attr_reader :options
|
12
|
+
attr_reader :storage
|
13
|
+
|
14
|
+
|
15
|
+
def self.options
|
16
|
+
@options ||= {
|
17
|
+
:storage => :fs,
|
18
|
+
:protocol => 'http',
|
19
|
+
:path => "/:name/:style/:id:extension",
|
20
|
+
:styles => {},
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# Initialize a new attachment by providing a name and the instance the attachment is associated with.
|
26
|
+
#
|
27
|
+
# Parameters:
|
28
|
+
#
|
29
|
+
# * name - The name for the attachment such as 'avatar' or 'photo'
|
30
|
+
# * instance - The instance the attachment is attached to
|
31
|
+
#
|
32
|
+
# Options:
|
33
|
+
#
|
34
|
+
# * :path - The location where the attachment is stored
|
35
|
+
# * :storage - The storage medium represented as a symbol such as ':s3' or ':fs'
|
36
|
+
# * :credentials - A file, hash, or path used to authenticate with the specified storage medium
|
37
|
+
|
38
|
+
def initialize(name, instance, options = {})
|
39
|
+
@name = name
|
40
|
+
@instance = instance
|
41
|
+
|
42
|
+
@options = self.class.options.merge(options)
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# Usage:
|
47
|
+
#
|
48
|
+
# @object.avatar.assign(...)
|
49
|
+
|
50
|
+
def assign(file)
|
51
|
+
@file = file
|
52
|
+
|
53
|
+
extension = File.extname(file.original_filename)
|
54
|
+
|
55
|
+
instance_set :size, file.size
|
56
|
+
instance_set :extension, extension
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Usage:
|
61
|
+
#
|
62
|
+
# @object.avatar.save
|
63
|
+
|
64
|
+
def save
|
65
|
+
@storage ||= Attached::Storage.medium(options[:storage], options[:credentials])
|
66
|
+
|
67
|
+
storage.save(self.file, self.path) if self.file
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# Usage:
|
72
|
+
#
|
73
|
+
# @object.avatar.destroy
|
74
|
+
|
75
|
+
def destroy
|
76
|
+
@storage ||= Attached::Storage.medium(options[:storage], options[:credentials])
|
77
|
+
|
78
|
+
storage.destroy(self.path)
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Usage:
|
83
|
+
#
|
84
|
+
# @object.avatar.url
|
85
|
+
# @object.avatar.url(:small)
|
86
|
+
# @object.avatar.url(:large)
|
87
|
+
|
88
|
+
def url(style = :original)
|
89
|
+
@storage ||= Attached::Storage.medium(options[:storage], options[:credentials])
|
90
|
+
|
91
|
+
return "#{options[:protocol]}://#{@storage.host}#{path(style)}"
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Access the URL
|
96
|
+
#
|
97
|
+
# Usage:
|
98
|
+
#
|
99
|
+
# @object.avatar.url
|
100
|
+
# @object.avatar.url(:small)
|
101
|
+
# @object.avatar.url(:large)
|
102
|
+
|
103
|
+
def path(style = :original)
|
104
|
+
path = String.new(options[:path])
|
105
|
+
|
106
|
+
path.gsub!(/:id/, instance.id.to_s)
|
107
|
+
path.gsub!(/:name/, name.to_s)
|
108
|
+
path.gsub!(/:style/, style.to_s)
|
109
|
+
path.gsub!(/:extension/, extension(style).to_s)
|
110
|
+
|
111
|
+
return path
|
112
|
+
end
|
113
|
+
|
114
|
+
# Access the size for an attachment.
|
115
|
+
#
|
116
|
+
# Usage:
|
117
|
+
#
|
118
|
+
# @object.avatar.size
|
119
|
+
|
120
|
+
def size
|
121
|
+
return instance_get(:size)
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
# Access the extension for an attachment.
|
126
|
+
#
|
127
|
+
# Usage:
|
128
|
+
#
|
129
|
+
# @object.avatar.extension
|
130
|
+
|
131
|
+
def extension(style)
|
132
|
+
return options[:styles][style][:extension] if style and options[:styles][style]
|
133
|
+
|
134
|
+
return instance_get(:extension)
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
|
141
|
+
# Helper function for setting instance variables.
|
142
|
+
#
|
143
|
+
# Usage:
|
144
|
+
#
|
145
|
+
# self.instance_set(size, 12345)
|
146
|
+
|
147
|
+
def instance_set(attribute, value)
|
148
|
+
setter = :"#{self.name}_#{attribute}="
|
149
|
+
self.instance.send(setter, value)
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
# Helper function for getting instance variables.
|
154
|
+
#
|
155
|
+
# Usage:
|
156
|
+
#
|
157
|
+
# self.instance_get(size)
|
158
|
+
|
159
|
+
def instance_get(attribute)
|
160
|
+
getter = :"#{self.name}_#{attribute}"
|
161
|
+
self.instance.send(getter)
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'attached/storage/base'
|
2
|
+
require 'attached/storage/fs'
|
3
|
+
require 'attached/storage/s3'
|
4
|
+
|
5
|
+
module Attached
|
6
|
+
module Storage
|
7
|
+
|
8
|
+
# Create a storage object given a medium and credentials.
|
9
|
+
#
|
10
|
+
# Usage:
|
11
|
+
#
|
12
|
+
# Attached::Storage.medium(:fs)
|
13
|
+
# Attached::Storage.medium(:s3)
|
14
|
+
|
15
|
+
def self.medium(storage = :fs, credentials = nil)
|
16
|
+
|
17
|
+
case storage
|
18
|
+
when :fs then return Attached::Storage::FS.new(credentials)
|
19
|
+
when :s3 then return Attached::Storage::S3.new(credentials)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'attached/storage/base'
|
2
|
+
|
3
|
+
module Attached
|
4
|
+
module Storage
|
5
|
+
class Base
|
6
|
+
|
7
|
+
|
8
|
+
# Helper for parsing credentials from a hash, file, or string.
|
9
|
+
#
|
10
|
+
# Usage:
|
11
|
+
#
|
12
|
+
# parse({...})
|
13
|
+
# parse(File.open(...))
|
14
|
+
# Parse("...")
|
15
|
+
|
16
|
+
def parse(credentials)
|
17
|
+
case credentials
|
18
|
+
when Hash then credentials
|
19
|
+
when File then YAML::load(credentials)[Rails.env]
|
20
|
+
when String then YAML::load(File.read(credentials))[Rails.env]
|
21
|
+
else raise ArgumentError.new("credentials must be a hash, file, or string")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Create a new file system storage interface supporting save and destroy operations.
|
27
|
+
#
|
28
|
+
# Usage:
|
29
|
+
#
|
30
|
+
# Base.new()
|
31
|
+
|
32
|
+
def initialize(credentials = nil)
|
33
|
+
raise NotImplementedError.new
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# Access the host (e.g. localhost:3000) for a storage service.
|
38
|
+
#
|
39
|
+
# Usage:
|
40
|
+
#
|
41
|
+
# storage.host
|
42
|
+
|
43
|
+
def host()
|
44
|
+
raise NotImplementedError.new
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
# Save a file to a given path (abstract).
|
49
|
+
#
|
50
|
+
# Parameters:
|
51
|
+
#
|
52
|
+
# * file - The file to save.
|
53
|
+
# * path - The path to save.
|
54
|
+
|
55
|
+
def save(file, path)
|
56
|
+
raise NotImplementedError.new
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Destroy a file at a given path (abstract).
|
61
|
+
#
|
62
|
+
# Parameters:
|
63
|
+
#
|
64
|
+
# * path - The path to destroy.
|
65
|
+
|
66
|
+
def destroy(path)
|
67
|
+
raise NotImplementedError.new
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Attached
|
2
|
+
module Storage
|
3
|
+
class FS < Base
|
4
|
+
|
5
|
+
|
6
|
+
# Create a new file system storage interface supporting save and destroy operations.
|
7
|
+
#
|
8
|
+
# Usage:
|
9
|
+
#
|
10
|
+
# FS.new()
|
11
|
+
|
12
|
+
def initialize(credentials = nil)
|
13
|
+
credentials = parse(credentials)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# Save a file to a given path on a file system.
|
18
|
+
#
|
19
|
+
# Parameters:
|
20
|
+
#
|
21
|
+
# * file - The file to save.
|
22
|
+
# * path - The path to save.
|
23
|
+
|
24
|
+
def save(file, path)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Destroy a file at a given path on a file system.
|
29
|
+
#
|
30
|
+
# Parameters:
|
31
|
+
#
|
32
|
+
# * path - The path to destroy.
|
33
|
+
|
34
|
+
def destroy(path)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Attached
|
2
|
+
module Storage
|
3
|
+
class S3 < Base
|
4
|
+
|
5
|
+
attr_reader :bucket
|
6
|
+
attr_reader :access_key_id
|
7
|
+
attr_reader :secret_access_key
|
8
|
+
|
9
|
+
|
10
|
+
# Create a new Amazon S3 storage interface supporting save and destroy operations.
|
11
|
+
#
|
12
|
+
# Usage:
|
13
|
+
#
|
14
|
+
# Attached::Storage::S3.new()
|
15
|
+
# Attached::Storage::S3.new("#{Rails.root}/config/s3.yml")
|
16
|
+
|
17
|
+
def initialize(credentials = "#{Rails.root}/config/s3.yml")
|
18
|
+
credentials = parse(credentials)
|
19
|
+
|
20
|
+
@bucket = credentials[:bucket] || credentials['bucket']
|
21
|
+
@access_key_id = credentials[:access_key_id] || credentials['access_key_id']
|
22
|
+
@secret_access_key = credentials[:secret_access_key] || credentials['secret_access_key']
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Access the host (e.g. bucket.s3.amazonaws.com) for a storage service.
|
27
|
+
#
|
28
|
+
# Usage:
|
29
|
+
#
|
30
|
+
# storage.host
|
31
|
+
|
32
|
+
def host()
|
33
|
+
"#{self.bucket}.s3.amazonaws.com"
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# Save a file to a given path on Amazon S3.
|
38
|
+
#
|
39
|
+
# Parameters:
|
40
|
+
#
|
41
|
+
# * file - The file to save.
|
42
|
+
# * path - The path to save.
|
43
|
+
|
44
|
+
def save(file, path)
|
45
|
+
connect()
|
46
|
+
AWS::S3::S3Object.store(path, file, bucket)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Destroy a file at a given path on Amazon S3.
|
51
|
+
#
|
52
|
+
# Parameters:
|
53
|
+
#
|
54
|
+
# * path - The path to destroy.
|
55
|
+
|
56
|
+
def destroy(path)
|
57
|
+
connect()
|
58
|
+
AWS::S3::S3Object.delete(path, bucket)
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
|
65
|
+
# Connect to an Amazon S3 server.
|
66
|
+
|
67
|
+
def connect
|
68
|
+
return AWS::S3::Base.establish_connection!(
|
69
|
+
:access_key_id => self.access_key_id,
|
70
|
+
:secret_access_key => self.secret_access_key
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attached
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Kevin Sylvestre
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-01 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: aws-s3
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
description: Attached is a Ruby on Rails cloud attachment and processor library inspired by Paperclip. Attached lets users push files to the cloud, then perform remote processing on the files.
|
34
|
+
email:
|
35
|
+
- kevin@ksylvest.com
|
36
|
+
executables: []
|
37
|
+
|
38
|
+
extensions: []
|
39
|
+
|
40
|
+
extra_rdoc_files: []
|
41
|
+
|
42
|
+
files:
|
43
|
+
- lib/attached/attachment.rb
|
44
|
+
- lib/attached/railtie.rb
|
45
|
+
- lib/attached/storage/base.rb
|
46
|
+
- lib/attached/storage/fs.rb
|
47
|
+
- lib/attached/storage/s3.rb
|
48
|
+
- lib/attached/storage.rb
|
49
|
+
- lib/attached.rb
|
50
|
+
- README.rdoc
|
51
|
+
- LICENSE
|
52
|
+
- Gemfile
|
53
|
+
has_rdoc: true
|
54
|
+
homepage: http://github.com/ksylvest/attached
|
55
|
+
licenses: []
|
56
|
+
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.3.7
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: An attachment library designed with cloud processors in mind
|
85
|
+
test_files: []
|
86
|
+
|