rails_uploads 0.1.5 → 0.2.0
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.
- data/README.rdoc +35 -9
- data/app/controllers/rails_uploads/application_controller.rb +1 -0
- data/app/controllers/rails_uploads/presets_controller.rb +2 -4
- data/lib/rails_uploads.rb +2 -0
- data/lib/rails_uploads/active_record/base.rb +60 -55
- data/lib/rails_uploads/magick/image.rb +3 -3
- data/lib/rails_uploads/railtie.rb +6 -1
- data/lib/rails_uploads/storages/local.rb +57 -0
- data/lib/rails_uploads/storages/s3.rb +61 -0
- data/lib/rails_uploads/types/file.rb +35 -43
- data/lib/rails_uploads/types/image.rb +12 -28
- data/lib/rails_uploads/validators/attachment_content_type_validator.rb +2 -4
- data/lib/rails_uploads/validators/attachment_presence_validator.rb +0 -2
- data/lib/rails_uploads/validators/attachment_size_validator.rb +4 -6
- data/lib/rails_uploads/version.rb +1 -1
- data/lib/tasks/rails_uploads_tasks.rake +31 -3
- data/test/dummy/app/models/file_upload.rb +1 -1
- data/test/dummy/app/models/image_upload.rb +1 -1
- data/test/dummy/app/models/validation_upload.rb +2 -2
- data/test/dummy/config/s3.yml +15 -0
- data/test/dummy/log/development.log +1 -0
- data/test/dummy/log/test.log +11581 -0
- data/test/dummy/public/uploads/images/{original/default.jpg → big/image.jpg} +0 -0
- data/test/dummy/public/uploads/images/small/image.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13687482983108968.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13687483348482658.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13687483563901100.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13687484108914220.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13687489381697390.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13687490968011022.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13687491524768450.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13687494425396302.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13687513450654020.jpg +0 -0
- data/test/dummy/{public/uploads/files/default.txt → tmp/uploads/files/13687514839373922.txt} +0 -0
- data/test/dummy/tmp/uploads/files/13688181722986792.jpg +0 -0
- data/test/dummy/tmp/uploads/files/13688181729459798.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13687484103672162.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13687484106303082.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13687489377129980.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13687489379459820.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13687490965463210.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13687491522552230.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688181724596422.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688181727051510.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688259257147068.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688280071286788.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688281527981960.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688360981527310.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688360983686640.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688977138132322.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688977290079510.jpg +0 -0
- data/test/dummy/tmp/uploads/images/big/13688978966174670.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687482977916958.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687482979328390.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687482981277580.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687483343313990.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687483344710930.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687483346647770.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687483558679350.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687483560070410.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687483562001660.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687484103672162.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687484106303082.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687489377129980.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687489379459820.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687490965463210.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13687491522552230.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688181723027610.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688181724596422.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688181727051510.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688259257147068.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688280071286788.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688281527981960.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688360981527310.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688360983686640.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688977138132322.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688977290079510.jpg +0 -0
- data/test/dummy/tmp/uploads/images/original/13688978966174670.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13687484103672162.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13687484106303082.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13687489377129980.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13687489379459820.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13687490965463210.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13687491522552230.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688181723027610.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688181724596422.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688181727051510.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688259257147068.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688280071286788.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688281527981960.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688360981527310.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688360983686640.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688977138132322.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688977290079510.jpg +0 -0
- data/test/dummy/tmp/uploads/images/small/13688978966174670.jpg +0 -0
- data/test/{generate_test.rb → integration/local_generate_test.rb} +12 -14
- data/test/test_helper.rb +29 -0
- data/test/unit/local_file_record_test.rb +20 -0
- data/test/unit/local_file_string_test.rb +23 -0
- data/test/unit/local_file_upload_test.rb +30 -0
- data/test/unit/local_image_record_test.rb +25 -0
- data/test/{image_string_test.rb → unit/local_image_string_test.rb} +19 -21
- data/test/unit/local_image_upload_test.rb +27 -0
- data/test/unit/local_records_test.rb +52 -0
- data/test/{validators_test.rb → unit/local_validators_test.rb} +15 -28
- data/test/unit/s3_file_record_tes.rb +21 -0
- data/test/unit/s3_file_string_tes.rb +24 -0
- data/test/unit/s3_file_upload_tes.rb +31 -0
- data/test/unit/s3_image_record_tes.rb +26 -0
- data/test/unit/s3_image_string_tes.rb +31 -0
- data/test/unit/s3_image_upload_tes.rb +28 -0
- data/test/unit/s3_records_tes.rb +56 -0
- data/test/unit/s3_validators_tes.rb +71 -0
- metadata +204 -25
- data/test/file_string_test.rb +0 -35
- data/test/file_upload_test.rb +0 -41
- data/test/image_presets_test.rb +0 -32
- data/test/image_upload_test.rb +0 -34
- data/test/rails_uploads_test.rb +0 -9
- data/test/records_test.rb +0 -55
data/README.rdoc
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
=== NOTE: From version 0.1.5 and above defaults must be
|
1
|
+
=== NOTE: From version 0.1.5 and above defaults must be in public folder
|
2
|
+
=== NOTE: From version 0.2.0 and above the use of path is deprecated
|
2
3
|
|
3
4
|
---
|
4
5
|
|
@@ -15,6 +16,9 @@ Put this line in your Gemfile:
|
|
15
16
|
|
16
17
|
Then bundle:
|
17
18
|
$ bundle
|
19
|
+
|
20
|
+
ImageMagick must be install, you can install it with homebrew:
|
21
|
+
brew install imagemagick
|
18
22
|
|
19
23
|
= Usage
|
20
24
|
|
@@ -45,6 +49,23 @@ Define presets in your application.rb
|
|
45
49
|
:custom => proc { |image| image.convert :resize => '100x100' } # ImageMagick wrapper to do whatever you want
|
46
50
|
}
|
47
51
|
config.uploads.default_presets = [:small] # Define the default presets for all models with attached images
|
52
|
+
config.uploads.storage = :local # The default it's local, you can use :s3 as well
|
53
|
+
|
54
|
+
If you want to use S3 create a s3.yml file in your config directory like this:
|
55
|
+
development:
|
56
|
+
bucket: development-bucket
|
57
|
+
access_key_id: development_access_key_id
|
58
|
+
secret_access_key: development_secret_access_key
|
59
|
+
|
60
|
+
test:
|
61
|
+
bucket: test-bucket
|
62
|
+
access_key_id: test_access_key_id
|
63
|
+
secret_access_key: test_secret_access_key
|
64
|
+
|
65
|
+
production:
|
66
|
+
bucket: production-bucket
|
67
|
+
access_key_id: production_access_key_id
|
68
|
+
secret_access_key: production_secret_access_key
|
48
69
|
|
49
70
|
The validation works very similar to paperclip:
|
50
71
|
class Model < ActiveRecord::Base
|
@@ -61,10 +82,9 @@ If you want to translate the errores the keys are:
|
|
61
82
|
errors.messages.attachment_content_type # :types
|
62
83
|
|
63
84
|
In your views:
|
64
|
-
a{ :href => record.file.
|
65
|
-
a{ :href => record.image.
|
66
|
-
a{ :href => record.image.
|
67
|
-
a{ :href => record.image.url(:big) } # If you want to use a base url
|
85
|
+
a{ :href => record.file.url } # To get the file url
|
86
|
+
a{ :href => record.image.url } # To get the original image
|
87
|
+
a{ :href => record.image.url(:big) } # To get the a thumb
|
68
88
|
|
69
89
|
In your forms:
|
70
90
|
= f.file_field :prop
|
@@ -73,15 +93,21 @@ In your forms:
|
|
73
93
|
|
74
94
|
== How can I use a cdn with this plugin?
|
75
95
|
|
76
|
-
Just define a base url in your application.rb
|
77
|
-
config.uploads.base_url = 'http://example.com'
|
96
|
+
Just define a base url in your application.rb:
|
97
|
+
config.uploads.base_url = 'http://cdn.example.com'
|
98
|
+
|
99
|
+
== Can I automatically create buckets?
|
100
|
+
|
101
|
+
Yes, use this rake task after create the s3.yml file:
|
102
|
+
rake uploads:s3:buckets:create
|
78
103
|
|
79
104
|
== How can I clean a preset?
|
80
105
|
|
81
|
-
Just remove the corresponding folder in uploads/images manually or with rake task:
|
82
|
-
rake uploads:preset:clean
|
106
|
+
Just remove the corresponding folder in uploads/images manually or with this rake task:
|
107
|
+
rake uploads:preset:clean NAME=preset
|
83
108
|
|
84
109
|
== How to migrate from versions before 0.1.0?
|
85
110
|
|
86
111
|
To migrate from versions before 0.1.0 you need to reorganize uploads with this task after define your presets in your application.rb:
|
87
112
|
rake uploads:migrate
|
113
|
+
|
@@ -1,16 +1,14 @@
|
|
1
1
|
module RailsUploads
|
2
2
|
class PresetsController < ApplicationController
|
3
3
|
|
4
|
-
layout false
|
5
|
-
|
6
4
|
def generate
|
7
5
|
filename = "#{params[:image]}.#{params[:format]}"
|
8
6
|
preset = params[:preset].gsub('-', '_').to_sym
|
9
|
-
if Rails.application.config.uploads.presets.has_key?
|
7
|
+
if Rails.application.config.uploads.presets.has_key? preset
|
10
8
|
image = RailsUploads::Types::Image.new(filename)
|
11
9
|
if image.exists? and !image.exists?(preset)
|
12
10
|
image.send :generate_preset, preset
|
13
|
-
redirect_to request.url, :cb => Random.rand(100000)
|
11
|
+
redirect_to request.url, :cb => Random.rand(100000)
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
data/lib/rails_uploads.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'rails_uploads/active_record/base'
|
2
2
|
require 'rails_uploads/magick/image'
|
3
|
+
require 'rails_uploads/storages/local'
|
4
|
+
require 'rails_uploads/storages/s3'
|
3
5
|
require 'rails_uploads/types/file'
|
4
6
|
require 'rails_uploads/types/image'
|
5
7
|
require 'rails_uploads/validators/base'
|
@@ -1,7 +1,59 @@
|
|
1
1
|
module RailsUploads
|
2
2
|
module ActiveRecord
|
3
3
|
module Base
|
4
|
-
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def build_attachment_instance(source, options)
|
12
|
+
klass = options.has_key?(:type) ? options[:type].to_s.classify : 'File'
|
13
|
+
RailsUploads::Types.const_get(klass).new(source, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_changed_attachments
|
17
|
+
@stored_attachments = []
|
18
|
+
@deleted_attachments = []
|
19
|
+
self.class.send(:attachments).each do |attr, options|
|
20
|
+
if changed_attributes.has_key? attr.to_s
|
21
|
+
stored = attributes[attr.to_s]
|
22
|
+
deleted = changed_attributes[attr.to_s]
|
23
|
+
add_changed_attachment stored, options, :stored if stored.present?
|
24
|
+
add_changed_attachment deleted, options, :deleted if deleted.present?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def iterate_attachments
|
30
|
+
self.class.send(:attachments).each do |attr, options|
|
31
|
+
next unless instance = send(attr)
|
32
|
+
yield instance
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_changed_attachment(source, options, type)
|
37
|
+
(type == :stored ? @stored_attachments : @deleted_attachments) << build_attachment_instance(source, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def store_attachments
|
41
|
+
iterate_attachments { |a| a.store }
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete_attachments
|
45
|
+
iterate_attachments { |a| a.delete }
|
46
|
+
end
|
47
|
+
|
48
|
+
def remove_stored_attachments
|
49
|
+
@stored_attachments.each { |a| a.delete }
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove_deleted_attachments
|
53
|
+
@deleted_attachments.each { |a| a.delete }
|
54
|
+
end
|
55
|
+
|
56
|
+
module ClassMethods
|
5
57
|
|
6
58
|
def self.extended(base)
|
7
59
|
[:image].each do |type|
|
@@ -15,15 +67,17 @@ module RailsUploads
|
|
15
67
|
|
16
68
|
def attached_file(*args)
|
17
69
|
options = args.extract_options!
|
18
|
-
options.reverse_merge! :
|
70
|
+
options.reverse_merge! type: :file
|
19
71
|
define_attachment *args.append(options)
|
20
72
|
end
|
21
73
|
|
22
74
|
def is_attachable?
|
23
|
-
|
24
|
-
end
|
75
|
+
attachments.present?
|
76
|
+
end
|
25
77
|
|
26
78
|
protected
|
79
|
+
|
80
|
+
attr_reader :attachments
|
27
81
|
|
28
82
|
def define_attachment(*args)
|
29
83
|
options = args.extract_options!
|
@@ -35,7 +89,6 @@ module RailsUploads
|
|
35
89
|
end
|
36
90
|
|
37
91
|
def make_attachable
|
38
|
-
send :include, RailsUploads::ActiveRecord::Base::Attachable
|
39
92
|
before_save :store_attachments, :check_changed_attachments
|
40
93
|
after_save :remove_deleted_attachments
|
41
94
|
before_destroy :delete_attachments
|
@@ -53,7 +106,7 @@ module RailsUploads
|
|
53
106
|
define_method "#{attr}=" do |value|
|
54
107
|
@attachments = {} if defined?(@attachments).nil?
|
55
108
|
if value.is_a? ActionDispatch::Http::UploadedFile or value.is_a? Rack::Test::UploadedFile
|
56
|
-
@attachments[attr] =
|
109
|
+
@attachments[attr] = build_attachment_instance(value, options)
|
57
110
|
super(@attachments[attr].filename)
|
58
111
|
end
|
59
112
|
end
|
@@ -64,59 +117,11 @@ module RailsUploads
|
|
64
117
|
@attachments = {} if defined?(@attachments).nil?
|
65
118
|
return @attachments[attr] if @attachments.has_key? attr
|
66
119
|
return nil if super().nil? and not options.has_key? :default
|
67
|
-
@attachments[attr] =
|
120
|
+
@attachments[attr] = build_attachment_instance(super(), options)
|
68
121
|
end
|
69
122
|
end
|
70
123
|
|
71
124
|
end
|
72
|
-
module Attachable
|
73
|
-
|
74
|
-
protected
|
75
|
-
|
76
|
-
def get_attachment_instance(source, options)
|
77
|
-
klass = options.has_key?(:type) ? options[:type].to_s.classify : 'File'
|
78
|
-
RailsUploads::Types.const_get(klass).new(source, options)
|
79
|
-
end
|
80
|
-
|
81
|
-
def check_changed_attachments
|
82
|
-
@stored_attachments = []
|
83
|
-
@deleted_attachments = []
|
84
|
-
self.class.instance_variable_get('@attachments').each do |attr, options|
|
85
|
-
if changed_attributes.has_key? attr.to_s
|
86
|
-
add_changed_attachment attributes[attr.to_s], options, :stored
|
87
|
-
add_changed_attachment changed_attributes[attr.to_s], options, :deleted
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def iterate_attachments
|
93
|
-
self.class.instance_variable_get('@attachments').each do |attr, options|
|
94
|
-
next unless value = send(attr)
|
95
|
-
yield value
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def add_changed_attachment(value, options, type)
|
100
|
-
(type == :stored ? @stored_attachments : @deleted_attachments) << get_attachment_instance(value, options) unless value.nil?
|
101
|
-
end
|
102
|
-
|
103
|
-
def store_attachments
|
104
|
-
iterate_attachments { |a| a.store }
|
105
|
-
end
|
106
|
-
|
107
|
-
def delete_attachments
|
108
|
-
iterate_attachments { |a| a.delete }
|
109
|
-
end
|
110
|
-
|
111
|
-
def remove_stored_attachments
|
112
|
-
@stored_attachments.each { |a| a.delete }
|
113
|
-
end
|
114
|
-
|
115
|
-
def remove_deleted_attachments
|
116
|
-
@deleted_attachments.each { |a| a.delete }
|
117
|
-
end
|
118
|
-
|
119
|
-
end
|
120
125
|
end
|
121
126
|
end
|
122
127
|
end
|
@@ -33,7 +33,7 @@ module RailsUploads
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def dimensions
|
36
|
-
identify(:
|
36
|
+
identify(format: '%wx%h') do |success, output|
|
37
37
|
success ? output.chomp.split('x').map(&:to_i) : []
|
38
38
|
end
|
39
39
|
end
|
@@ -49,13 +49,13 @@ module RailsUploads
|
|
49
49
|
def resize_to_fill(max_width, max_height)
|
50
50
|
width, height = dimensions
|
51
51
|
scale = [max_width/width.to_f, max_height/height.to_f].max
|
52
|
-
convert :
|
52
|
+
convert resize: "#{(scale*width).to_i}x#{(scale*height).to_i}", gravity: 'center', crop: "#{max_width}x#{max_height}+0+0"
|
53
53
|
end
|
54
54
|
|
55
55
|
def resize_to_fit(max_width, max_height)
|
56
56
|
width, height = dimensions
|
57
57
|
scale = [max_width/width.to_f, max_height/height.to_f].min
|
58
|
-
convert :
|
58
|
+
convert resize: "#{(scale*width).to_i}x#{(scale*height).to_i}", gravity: 'center'
|
59
59
|
end
|
60
60
|
|
61
61
|
protected
|
@@ -5,9 +5,14 @@ module RailsUploads
|
|
5
5
|
config.uploads.presets = {}
|
6
6
|
config.uploads.default_presets = []
|
7
7
|
config.uploads.base_url = ''
|
8
|
+
config.uploads.storage = :local
|
8
9
|
|
9
10
|
initializer 'rails_uploads' do
|
10
|
-
::ActiveRecord::Base.send :
|
11
|
+
::ActiveRecord::Base.send :include, RailsUploads::ActiveRecord::Base
|
12
|
+
if config.uploads.storage == :s3
|
13
|
+
require 'aws-sdk'
|
14
|
+
RailsUploads::Storages::S3.config = YAML.load_file(Rails.root.join('config', 's3.yml'))
|
15
|
+
end
|
11
16
|
end
|
12
17
|
|
13
18
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module RailsUploads
|
2
|
+
module Storages
|
3
|
+
class Local
|
4
|
+
|
5
|
+
def initialize(tmp)
|
6
|
+
@tmp = tmp
|
7
|
+
end
|
8
|
+
|
9
|
+
def exists?(path)
|
10
|
+
::File.exists? realpath(path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def size(path)
|
14
|
+
::File.size realpath(path)
|
15
|
+
end
|
16
|
+
|
17
|
+
def url(path)
|
18
|
+
::File.join Rails.application.config.uploads.base_url, path
|
19
|
+
end
|
20
|
+
|
21
|
+
def store(upload, path)
|
22
|
+
create_dir realpath(path)
|
23
|
+
upload.rewind # Hack to avoid empty files
|
24
|
+
::File.open(realpath(path), 'wb') do |file|
|
25
|
+
while chunk = upload.read(16 * 1024)
|
26
|
+
file.write(chunk)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete(path)
|
32
|
+
::File.delete realpath(path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def magick(source, output, upload)
|
36
|
+
create_dir realpath(output)
|
37
|
+
yield RailsUploads::Magick::Image.new(realpath(source), realpath(output))
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def realpath(path)
|
43
|
+
base_path.join path
|
44
|
+
end
|
45
|
+
|
46
|
+
def base_path
|
47
|
+
Rails.root.join @tmp ? 'tmp' : 'public'
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_dir(path)
|
51
|
+
dir = base_path.join('uploads', path).dirname
|
52
|
+
FileUtils.mkdir_p dir unless ::File.directory? dir
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module RailsUploads
|
2
|
+
module Storages
|
3
|
+
class S3
|
4
|
+
|
5
|
+
cattr_accessor :config
|
6
|
+
|
7
|
+
def initialize(test)
|
8
|
+
config = self.class.config[test ? 'test' : 'production']
|
9
|
+
AWS.config access_key_id: config['access_key_id'], secret_access_key: config['secret_access_key']
|
10
|
+
@bucket = AWS::S3.new.buckets[config['bucket']]
|
11
|
+
@tmp = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def exists?(path)
|
15
|
+
object(path).exists?
|
16
|
+
end
|
17
|
+
|
18
|
+
def size(path)
|
19
|
+
object(path).content_length
|
20
|
+
end
|
21
|
+
|
22
|
+
def url(path)
|
23
|
+
base_url = Rails.application.config.uploads.base_url
|
24
|
+
base_url.present? ? ::File.join(base_url, path) : object(path).public_url(secure: false)
|
25
|
+
end
|
26
|
+
|
27
|
+
def store(upload, path)
|
28
|
+
@bucket.objects.create(path, Pathname.new(upload.path)).acl = :public_read
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete(path)
|
32
|
+
object(path).delete
|
33
|
+
end
|
34
|
+
|
35
|
+
def magick(source, output, upload)
|
36
|
+
if @tmp[source].blank?
|
37
|
+
if upload.present?
|
38
|
+
@tmp[source] = upload.path
|
39
|
+
else
|
40
|
+
tmp = Tempfile.open('s3', Rails.root.join('tmp')) do |file|
|
41
|
+
object(source).read do |chunk|
|
42
|
+
file.write(chunk)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
@tmp[source] = tmp.path
|
46
|
+
end
|
47
|
+
end
|
48
|
+
tmp = Tempfile.new('s3', Rails.root.join('tmp'))
|
49
|
+
yield RailsUploads::Magick::Image.new(@tmp[source], tmp.path)
|
50
|
+
store tmp, output
|
51
|
+
end
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
def object(path)
|
56
|
+
@bucket.objects[path]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -7,45 +7,32 @@ module RailsUploads
|
|
7
7
|
@upload = source
|
8
8
|
@stored = false
|
9
9
|
@default = false
|
10
|
+
@storage = build_storage(:local)
|
10
11
|
elsif source.is_a? String
|
11
12
|
@upload = false
|
12
13
|
@filename = source
|
13
14
|
@stored = true
|
14
15
|
@default = false
|
16
|
+
@storage = build_storage
|
15
17
|
elsif options.has_key? :default
|
16
18
|
@upload = false
|
17
19
|
@filename = options[:default]
|
18
20
|
@stored = true
|
19
21
|
@default = true
|
22
|
+
@storage = build_storage
|
20
23
|
end
|
21
24
|
@deleted = false
|
22
25
|
@options = options
|
23
26
|
end
|
24
27
|
|
25
|
-
def is_default?
|
26
|
-
@default
|
27
|
-
end
|
28
|
-
|
29
|
-
def is_upload?
|
30
|
-
@upload != false
|
31
|
-
end
|
32
|
-
|
33
|
-
def is_stored?
|
34
|
-
@stored
|
35
|
-
end
|
36
|
-
|
37
|
-
def is_deleted?
|
38
|
-
@deleted
|
39
|
-
end
|
40
|
-
|
41
28
|
def exists?(*args)
|
42
29
|
return false if is_deleted?
|
43
|
-
|
30
|
+
storage.exists? path(*args)
|
44
31
|
end
|
45
32
|
|
46
33
|
def size(*args)
|
47
34
|
return 0 if is_deleted?
|
48
|
-
|
35
|
+
storage.size path(*args)
|
49
36
|
end
|
50
37
|
|
51
38
|
def extname
|
@@ -60,37 +47,29 @@ module RailsUploads
|
|
60
47
|
|
61
48
|
def path(*args)
|
62
49
|
return nil if is_deleted?
|
63
|
-
|
50
|
+
is_stored? ? destination_path(*args) : @upload.path
|
64
51
|
end
|
65
52
|
|
66
53
|
def url(*args)
|
67
|
-
return nil if is_deleted?
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
def realpath(*args)
|
72
|
-
return nil if is_deleted?
|
73
|
-
::File.expand_path(is_stored? ? destination_path(*args) : @upload.path)
|
54
|
+
return nil if is_deleted? or not is_stored?
|
55
|
+
storage.url path(*args)
|
74
56
|
end
|
75
57
|
|
76
58
|
def store
|
77
59
|
if not is_stored? and is_upload?
|
78
|
-
|
79
|
-
@upload
|
80
|
-
::File.open(destination_path, 'wb') do |file|
|
81
|
-
while chunk = @upload.read(16 * 1024)
|
82
|
-
file.write(chunk)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
@stored = true
|
60
|
+
@storage = build_storage
|
61
|
+
storage.store @upload, destination_path
|
86
62
|
yield if block_given?
|
63
|
+
@stored = true
|
64
|
+
@deleted = false
|
87
65
|
end
|
88
66
|
end
|
89
67
|
|
90
68
|
def delete
|
91
69
|
if not is_default? and is_stored? and exists?
|
92
|
-
|
70
|
+
storage.delete path
|
93
71
|
yield if block_given?
|
72
|
+
@storage = build_storage(:local) if @upload.present?
|
94
73
|
@stored = false
|
95
74
|
@deleted = true
|
96
75
|
end
|
@@ -98,20 +77,33 @@ module RailsUploads
|
|
98
77
|
|
99
78
|
protected
|
100
79
|
|
101
|
-
def
|
102
|
-
|
80
|
+
def build_storage(type=nil)
|
81
|
+
tmp = (Rails.env == 'test' and not is_default?)
|
82
|
+
type = (type or Rails.application.config.uploads.storage)
|
83
|
+
RailsUploads::Storages.const_get(type.to_s.classify).new(tmp)
|
103
84
|
end
|
104
85
|
|
105
|
-
def
|
106
|
-
|
107
|
-
FileUtils.mkdir_p dir unless ::File.directory? dir
|
86
|
+
def storage
|
87
|
+
@storage
|
108
88
|
end
|
109
89
|
|
110
|
-
def
|
111
|
-
|
90
|
+
def is_default?
|
91
|
+
@default
|
92
|
+
end
|
93
|
+
|
94
|
+
def is_upload?
|
95
|
+
@upload != false
|
112
96
|
end
|
113
97
|
|
114
|
-
def
|
98
|
+
def is_stored?
|
99
|
+
@stored
|
100
|
+
end
|
101
|
+
|
102
|
+
def is_deleted?
|
103
|
+
@deleted
|
104
|
+
end
|
105
|
+
|
106
|
+
def destination_path(*args)
|
115
107
|
::File.join 'uploads', store_path(*args), filename
|
116
108
|
end
|
117
109
|
|