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.
Files changed (120) hide show
  1. data/README.rdoc +35 -9
  2. data/app/controllers/rails_uploads/application_controller.rb +1 -0
  3. data/app/controllers/rails_uploads/presets_controller.rb +2 -4
  4. data/lib/rails_uploads.rb +2 -0
  5. data/lib/rails_uploads/active_record/base.rb +60 -55
  6. data/lib/rails_uploads/magick/image.rb +3 -3
  7. data/lib/rails_uploads/railtie.rb +6 -1
  8. data/lib/rails_uploads/storages/local.rb +57 -0
  9. data/lib/rails_uploads/storages/s3.rb +61 -0
  10. data/lib/rails_uploads/types/file.rb +35 -43
  11. data/lib/rails_uploads/types/image.rb +12 -28
  12. data/lib/rails_uploads/validators/attachment_content_type_validator.rb +2 -4
  13. data/lib/rails_uploads/validators/attachment_presence_validator.rb +0 -2
  14. data/lib/rails_uploads/validators/attachment_size_validator.rb +4 -6
  15. data/lib/rails_uploads/version.rb +1 -1
  16. data/lib/tasks/rails_uploads_tasks.rake +31 -3
  17. data/test/dummy/app/models/file_upload.rb +1 -1
  18. data/test/dummy/app/models/image_upload.rb +1 -1
  19. data/test/dummy/app/models/validation_upload.rb +2 -2
  20. data/test/dummy/config/s3.yml +15 -0
  21. data/test/dummy/log/development.log +1 -0
  22. data/test/dummy/log/test.log +11581 -0
  23. data/test/dummy/public/uploads/images/{original/default.jpg → big/image.jpg} +0 -0
  24. data/test/dummy/public/uploads/images/small/image.jpg +0 -0
  25. data/test/dummy/tmp/uploads/files/13687482983108968.jpg +0 -0
  26. data/test/dummy/tmp/uploads/files/13687483348482658.jpg +0 -0
  27. data/test/dummy/tmp/uploads/files/13687483563901100.jpg +0 -0
  28. data/test/dummy/tmp/uploads/files/13687484108914220.jpg +0 -0
  29. data/test/dummy/tmp/uploads/files/13687489381697390.jpg +0 -0
  30. data/test/dummy/tmp/uploads/files/13687490968011022.jpg +0 -0
  31. data/test/dummy/tmp/uploads/files/13687491524768450.jpg +0 -0
  32. data/test/dummy/tmp/uploads/files/13687494425396302.jpg +0 -0
  33. data/test/dummy/tmp/uploads/files/13687513450654020.jpg +0 -0
  34. data/test/dummy/{public/uploads/files/default.txt → tmp/uploads/files/13687514839373922.txt} +0 -0
  35. data/test/dummy/tmp/uploads/files/13688181722986792.jpg +0 -0
  36. data/test/dummy/tmp/uploads/files/13688181729459798.jpg +0 -0
  37. data/test/dummy/tmp/uploads/images/big/13687484103672162.jpg +0 -0
  38. data/test/dummy/tmp/uploads/images/big/13687484106303082.jpg +0 -0
  39. data/test/dummy/tmp/uploads/images/big/13687489377129980.jpg +0 -0
  40. data/test/dummy/tmp/uploads/images/big/13687489379459820.jpg +0 -0
  41. data/test/dummy/tmp/uploads/images/big/13687490965463210.jpg +0 -0
  42. data/test/dummy/tmp/uploads/images/big/13687491522552230.jpg +0 -0
  43. data/test/dummy/tmp/uploads/images/big/13688181724596422.jpg +0 -0
  44. data/test/dummy/tmp/uploads/images/big/13688181727051510.jpg +0 -0
  45. data/test/dummy/tmp/uploads/images/big/13688259257147068.jpg +0 -0
  46. data/test/dummy/tmp/uploads/images/big/13688280071286788.jpg +0 -0
  47. data/test/dummy/tmp/uploads/images/big/13688281527981960.jpg +0 -0
  48. data/test/dummy/tmp/uploads/images/big/13688360981527310.jpg +0 -0
  49. data/test/dummy/tmp/uploads/images/big/13688360983686640.jpg +0 -0
  50. data/test/dummy/tmp/uploads/images/big/13688977138132322.jpg +0 -0
  51. data/test/dummy/tmp/uploads/images/big/13688977290079510.jpg +0 -0
  52. data/test/dummy/tmp/uploads/images/big/13688978966174670.jpg +0 -0
  53. data/test/dummy/tmp/uploads/images/original/13687482977916958.jpg +0 -0
  54. data/test/dummy/tmp/uploads/images/original/13687482979328390.jpg +0 -0
  55. data/test/dummy/tmp/uploads/images/original/13687482981277580.jpg +0 -0
  56. data/test/dummy/tmp/uploads/images/original/13687483343313990.jpg +0 -0
  57. data/test/dummy/tmp/uploads/images/original/13687483344710930.jpg +0 -0
  58. data/test/dummy/tmp/uploads/images/original/13687483346647770.jpg +0 -0
  59. data/test/dummy/tmp/uploads/images/original/13687483558679350.jpg +0 -0
  60. data/test/dummy/tmp/uploads/images/original/13687483560070410.jpg +0 -0
  61. data/test/dummy/tmp/uploads/images/original/13687483562001660.jpg +0 -0
  62. data/test/dummy/tmp/uploads/images/original/13687484103672162.jpg +0 -0
  63. data/test/dummy/tmp/uploads/images/original/13687484106303082.jpg +0 -0
  64. data/test/dummy/tmp/uploads/images/original/13687489377129980.jpg +0 -0
  65. data/test/dummy/tmp/uploads/images/original/13687489379459820.jpg +0 -0
  66. data/test/dummy/tmp/uploads/images/original/13687490965463210.jpg +0 -0
  67. data/test/dummy/tmp/uploads/images/original/13687491522552230.jpg +0 -0
  68. data/test/dummy/tmp/uploads/images/original/13688181723027610.jpg +0 -0
  69. data/test/dummy/tmp/uploads/images/original/13688181724596422.jpg +0 -0
  70. data/test/dummy/tmp/uploads/images/original/13688181727051510.jpg +0 -0
  71. data/test/dummy/tmp/uploads/images/original/13688259257147068.jpg +0 -0
  72. data/test/dummy/tmp/uploads/images/original/13688280071286788.jpg +0 -0
  73. data/test/dummy/tmp/uploads/images/original/13688281527981960.jpg +0 -0
  74. data/test/dummy/tmp/uploads/images/original/13688360981527310.jpg +0 -0
  75. data/test/dummy/tmp/uploads/images/original/13688360983686640.jpg +0 -0
  76. data/test/dummy/tmp/uploads/images/original/13688977138132322.jpg +0 -0
  77. data/test/dummy/tmp/uploads/images/original/13688977290079510.jpg +0 -0
  78. data/test/dummy/tmp/uploads/images/original/13688978966174670.jpg +0 -0
  79. data/test/dummy/tmp/uploads/images/small/13687484103672162.jpg +0 -0
  80. data/test/dummy/tmp/uploads/images/small/13687484106303082.jpg +0 -0
  81. data/test/dummy/tmp/uploads/images/small/13687489377129980.jpg +0 -0
  82. data/test/dummy/tmp/uploads/images/small/13687489379459820.jpg +0 -0
  83. data/test/dummy/tmp/uploads/images/small/13687490965463210.jpg +0 -0
  84. data/test/dummy/tmp/uploads/images/small/13687491522552230.jpg +0 -0
  85. data/test/dummy/tmp/uploads/images/small/13688181723027610.jpg +0 -0
  86. data/test/dummy/tmp/uploads/images/small/13688181724596422.jpg +0 -0
  87. data/test/dummy/tmp/uploads/images/small/13688181727051510.jpg +0 -0
  88. data/test/dummy/tmp/uploads/images/small/13688259257147068.jpg +0 -0
  89. data/test/dummy/tmp/uploads/images/small/13688280071286788.jpg +0 -0
  90. data/test/dummy/tmp/uploads/images/small/13688281527981960.jpg +0 -0
  91. data/test/dummy/tmp/uploads/images/small/13688360981527310.jpg +0 -0
  92. data/test/dummy/tmp/uploads/images/small/13688360983686640.jpg +0 -0
  93. data/test/dummy/tmp/uploads/images/small/13688977138132322.jpg +0 -0
  94. data/test/dummy/tmp/uploads/images/small/13688977290079510.jpg +0 -0
  95. data/test/dummy/tmp/uploads/images/small/13688978966174670.jpg +0 -0
  96. data/test/{generate_test.rb → integration/local_generate_test.rb} +12 -14
  97. data/test/test_helper.rb +29 -0
  98. data/test/unit/local_file_record_test.rb +20 -0
  99. data/test/unit/local_file_string_test.rb +23 -0
  100. data/test/unit/local_file_upload_test.rb +30 -0
  101. data/test/unit/local_image_record_test.rb +25 -0
  102. data/test/{image_string_test.rb → unit/local_image_string_test.rb} +19 -21
  103. data/test/unit/local_image_upload_test.rb +27 -0
  104. data/test/unit/local_records_test.rb +52 -0
  105. data/test/{validators_test.rb → unit/local_validators_test.rb} +15 -28
  106. data/test/unit/s3_file_record_tes.rb +21 -0
  107. data/test/unit/s3_file_string_tes.rb +24 -0
  108. data/test/unit/s3_file_upload_tes.rb +31 -0
  109. data/test/unit/s3_image_record_tes.rb +26 -0
  110. data/test/unit/s3_image_string_tes.rb +31 -0
  111. data/test/unit/s3_image_upload_tes.rb +28 -0
  112. data/test/unit/s3_records_tes.rb +56 -0
  113. data/test/unit/s3_validators_tes.rb +71 -0
  114. metadata +204 -25
  115. data/test/file_string_test.rb +0 -35
  116. data/test/file_upload_test.rb +0 -41
  117. data/test/image_presets_test.rb +0 -32
  118. data/test/image_upload_test.rb +0 -34
  119. data/test/rails_uploads_test.rb +0 -9
  120. 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 put in public/uploads folder
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.path } # To get the file
65
- a{ :href => record.image.path } # To get the original image
66
- a{ :href => record.image.path(:big) } # To get the thumb
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 and use url method instead of path:
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[preset]
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,4 +1,5 @@
1
1
  module RailsUploads
2
2
  class ApplicationController < ActionController::Base
3
+
3
4
  end
4
5
  end
@@ -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?(preset)
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) and return
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
- module NonAttachable
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! :type => :file
70
+ options.reverse_merge! type: :file
19
71
  define_attachment *args.append(options)
20
72
  end
21
73
 
22
74
  def is_attachable?
23
- not defined?(@attachments).nil?
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] = get_attachment_instance(value, options)
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] = get_attachment_instance(super(), options)
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(:format => '%wx%h') do |success, output|
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 :resize => "#{(scale*width).to_i}x#{(scale*height).to_i}", :gravity => 'center', :crop => "#{max_width}x#{max_height}+0+0"
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 :resize => "#{(scale*width).to_i}x#{(scale*height).to_i}", :gravity => 'center'
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 :extend, RailsUploads::ActiveRecord::Base::NonAttachable
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
- ::File.exists? realpath(*args)
30
+ storage.exists? path(*args)
44
31
  end
45
32
 
46
33
  def size(*args)
47
34
  return 0 if is_deleted?
48
- ::File.size realpath(*args)
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
- ::File.join '', public_path(*args)
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
- ::File.join Rails.application.config.uploads.base_url, path(*args)
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
- create_dir
79
- @upload.rewind # Hack to avoid empty files
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
- ::File.delete realpath
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 base_path
102
- Rails.root.join (Rails.env == 'test' and not is_default?) ? 'tmp' : 'public'
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 create_dir(*args)
106
- dir = base_path.join('uploads', store_path(*args))
107
- FileUtils.mkdir_p dir unless ::File.directory? dir
86
+ def storage
87
+ @storage
108
88
  end
109
89
 
110
- def destination_path(*args)
111
- base_path.join public_path(*args)
90
+ def is_default?
91
+ @default
92
+ end
93
+
94
+ def is_upload?
95
+ @upload != false
112
96
  end
113
97
 
114
- def public_path(*args)
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