carrierwave 0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of carrierwave might be problematic. Click here for more details.

@@ -0,0 +1,4 @@
1
+ scope 'merb-gen' do
2
+ dir = File.join(File.dirname(__FILE__), 'lib', 'generators/')
3
+ Merb.add_generators dir + 'uploader_generator'
4
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 YOUR NAME
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.
@@ -0,0 +1,242 @@
1
+ # CarrierWave
2
+
3
+ This plugin for Merb and Rails provides a simple and extremely flexible way to upload files.
4
+
5
+ ## Getting Started
6
+
7
+ At the moment you are going to have to grab it here from github and install it yourself.
8
+
9
+ In Merb, add it as a dependency to your config/dependencies.rb:
10
+
11
+ dependency 'carrierwave'
12
+
13
+ In Rails, add it to your environment.rb:
14
+
15
+ config.gem "carrierwave"
16
+
17
+ ## Quick Start
18
+
19
+ Start off by generating an uploader:
20
+
21
+ merb-gen uploader Avatar
22
+
23
+ or in Rails:
24
+
25
+ script/generate uploader Avatar
26
+
27
+ this should give you a file in:
28
+
29
+ app/uploaders/avatar_uploader.rb
30
+
31
+ Check out this file for some hints on how you can customize your uploader. It should look something like this:
32
+
33
+ class AvatarUploader < CarrierWave::Uploader
34
+ storage :file
35
+ end
36
+
37
+ You can use your uploader class to store and retrieve files like this:
38
+
39
+ uploader = AvatarUploader.new
40
+
41
+ uploader.store!(my_file)
42
+
43
+ uploader.retrieve_from_store!('my_file.png')
44
+
45
+ CarrierWave gives you a `store` for permanent storage, and a `cache` for temporary storage. You can use different stores, at the moment a filesystem store and an Amazon S3 store are bundled.
46
+
47
+ Most of the time you are going to want to use CarrierWave together with an ORM. It is quite simple to mount uploaders on columns in your model, so you can simply assign files and get going:
48
+
49
+ ### ActiveRecord
50
+
51
+ First require the activerecord extension:
52
+
53
+ require 'carrierwave/orm/activerecord
54
+
55
+ You don't need to do this if you are using Merb or Rails.
56
+
57
+ Open your model file, and do something like:
58
+
59
+ class User < ActiveRecord::Base
60
+ mount_uploader :avatar, AvatarUploader
61
+ end
62
+
63
+ Now you can upload files!
64
+
65
+ u = User.new
66
+ u.avatar = params[:file]
67
+ u.avatar = File.open('somewhere')
68
+ u.save!
69
+ u.avatar.url # => '/url/to/file.png'
70
+ u.avatar.current_path # => 'path/to/file.png'
71
+
72
+ ### DataMapper
73
+
74
+ First require the activerecord extension:
75
+
76
+ require 'carrierwave/orm/datamapper
77
+
78
+ You don't need to do this if you are using Merb or Rails.
79
+
80
+ Open your model file, and do something like:
81
+
82
+ class User
83
+ include DataMapper::Resource
84
+
85
+ mount_uploader :avatar, AvatarUploader
86
+ end
87
+
88
+ Now you can upload files!
89
+
90
+ u = User.new
91
+ u.avatar = params[:file]
92
+ u.avatar = File.open('somewhere')
93
+ u.save!
94
+ u.avatar.url # => '/url/to/file.png'
95
+ u.avatar.current_path # => 'path/to/file.png'
96
+
97
+ ## Changing the storage directory
98
+
99
+ In order to change where uploaded files are put, just override the `store_dir` method:
100
+
101
+ class MyUploader < CarrierWave::Uploader
102
+ def store_dir
103
+ 'public/my/upload/directory'
104
+ end
105
+ end
106
+
107
+ This works for the file storage as well as Amazon S3.
108
+
109
+ ## Adding versions
110
+
111
+ Often you'll want to add different versions of the same file. The classic example is image thumbnails. There is built in support for this:
112
+
113
+ class MyUploader < CarrierWave::Uploader
114
+ include CarrierWave::RMagick
115
+
116
+ process :resize => [800, 800]
117
+
118
+ version :thumb do
119
+ process :crop_resized => [200,200]
120
+ end
121
+
122
+ end
123
+
124
+ When this uploader is used, an uploaded image would be scaled to be no larger than 800 by 800 pixels. A version called thumb is then created, which is scaled and cropped to exactly 200 by 200 pixels. The uploader could be used like this:
125
+
126
+ uploader = AvatarUploader.new
127
+ uploader.store!(my_file) # size: 1024x768
128
+
129
+ uploader.url # => '/url/to/my_file.png' # size: 800x600
130
+ uploader.thumb.url # => '/url/to/thumb_my_file.png' # size: 200x200
131
+
132
+ One important thing to remember is that process is called *before* versions are created. This can cut down on processing cost.
133
+
134
+ ## Making uploads work across form redisplays
135
+
136
+ Often you'll notice that uploaded files disappear when a validation
137
+ fails. CarrierWave has a feature that makes it easy to remember the
138
+ uploaded file even in that case. Suppose your `user` model has an uploader mounted on `avatar` file, just add a hidden field called `avatar_cache`.
139
+ In Rails, this would look like this:
140
+
141
+ <% form_for @user do |f| %>
142
+ <p>
143
+ <label>My Avatar</label>
144
+ <%= f.file_field :avatar %>
145
+ <%= f.hidden_field :avatar_cache %>
146
+ </p>
147
+ <% end %>
148
+
149
+ It might be a good idea to show th user that a file has been uploaded,
150
+ in the case of images, a small thumbnail would be a good indicator:
151
+
152
+ <% form_for @user do |f| %>
153
+ <p>
154
+ <label>My Avatar</label>
155
+ <%= image_tag(@user.avatar.url) if @user.avatar %>
156
+ <%= f.file_field :avatar %>
157
+ <%= f.hidden_field :avatar_cache %>
158
+ </p>
159
+ <% end %>
160
+
161
+ ## What's in that uploader file?
162
+
163
+ The fact that uploaders are separate classes in CarrierWave is a big advantage. What this means for you is:
164
+
165
+ #### Less magic
166
+
167
+ In order to customize your uploader, all you need to do is override methods and use normal, clear and simple Ruby code. That means no `alias_method_chain`'ing to hook into the upload process, no messing around with weird extensions. The code in CarrierWave is very simple and easy because of this.
168
+
169
+ #### Easier to test
170
+
171
+ How do you test file uploads? I always found this ridiculously hard. A separate class means you can test is separately, which is nicer, easier and more maintainable.
172
+
173
+ #### More Flexible
174
+
175
+ Many of the things you can do in CarrierWave are hard, or impossible to do in other file upload plugins, and have previously required you to roll your own. Now you can get all the flexibility without having to write low level stuff.
176
+
177
+ #### Easy to extend
178
+
179
+ CarrierWave has support for a few different image manipulation libraries. These need *no* code to hook into CarrierWave, because they are simple modules. If you want to write your own manipulation library (doesn't need to be for images), you can do the same.
180
+
181
+ ## Using Amazon S3
182
+
183
+ You'll need to configure a bucket, access id and secret key like this:
184
+
185
+ CarrierWave.config[:s3][:access_key_id] = 'xxxxxx'
186
+ CarrierWave.config[:s3][:secret_access_key] = 'xxxxxx'
187
+ CarrierWave.config[:s3][:bucket] = 'name_of_bucket'
188
+
189
+ Do this in an initializer in Rails, and in a `before_app_loads` block in Merb.
190
+
191
+ And then in your uploader, set the storage to :s3
192
+
193
+ class AvatarUploader < CarrierWave::Uploader
194
+ storage :s3
195
+ end
196
+
197
+ That's it! You can still use the `CarrierWave::Uploader#url` method to return the url to the file on Amazon S3
198
+
199
+ ## Using RMagick
200
+
201
+ If you're uploading images, you'll probably want to manipulate them in some way, you might want to create thumbnail images for example. CarrierWave comes with a small library to make manipulating images with RMagick easier. It's not loaded by default so you'll need to require it:
202
+
203
+ require 'carrierwave/processing/rmagick'
204
+
205
+ You'll also need to include it in your Uploader:
206
+
207
+ class AvatarUploader < CarrierWave::Uploader
208
+ include CarrierWave::RMagick
209
+ end
210
+
211
+ The RMagick module gives you a few methods, like `CarrierWave::RMagick#crop_resized` which manipulate the image file in some way. You can set a `process` callback, which will call that method any time a file is uploaded.
212
+
213
+ class AvatarUploader < CarrierWave::Uploader
214
+ include CarrierWave::RMagick
215
+
216
+ process :crop_resized => [200, 200]
217
+ process :convert => 'png'
218
+
219
+ def filename
220
+ super + '.png'
221
+ end
222
+ end
223
+
224
+ Check out the manipulate! method, which makes it easy for you to write your own manipulation methods.
225
+
226
+ ## Using ImageScience
227
+
228
+ ImageScience works the same way as RMagick. As with RMagick you'll need to require it:
229
+
230
+ require 'carrierwave/processing/image_science'
231
+
232
+ And then include it in your model:
233
+
234
+ class AvatarUploader < CarrierWave::Uploader
235
+ include CarrierWave::ImageScience
236
+
237
+ process :crop_resized => [200, 200]
238
+ end
239
+
240
+ ## Read the source
241
+
242
+ CarrierWave is still young, but most of it is pretty well documented. Just dig in and look at the source for more in-depth explanation of what things are doing.
@@ -0,0 +1,96 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+
4
+ require 'yard'
5
+ require 'spec/rake/spectask'
6
+ require 'cucumber/rake/task'
7
+
8
+ NAME = "carrierwave"
9
+ GEM_VERSION = "0.1"
10
+ AUTHOR = "Jonas Nicklas"
11
+ EMAIL = "jonas.nicklas@gmail.com"
12
+ HOMEPAGE = "http://www.example.com"
13
+ SUMMARY = "Simple and powerful uploads for Merb and Rails"
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.rubyforge_project = 'carrierwave'
17
+ s.name = NAME
18
+ s.version = GEM_VERSION
19
+ s.platform = Gem::Platform::RUBY
20
+ s.has_rdoc = true
21
+ s.extra_rdoc_files = ["README.md", "LICENSE", 'TODO']
22
+ s.summary = SUMMARY
23
+ s.description = s.summary
24
+ s.author = AUTHOR
25
+ s.email = EMAIL
26
+ s.homepage = HOMEPAGE
27
+ s.require_path = 'lib'
28
+ s.files = %w(LICENSE Generators README.md Rakefile TODO) + Dir.glob("{lib,spec,rails_generators}/**/*")
29
+
30
+ end
31
+
32
+ # Try these:
33
+ #
34
+ # rake features
35
+ # rake features PROFILE=html
36
+ Cucumber::Rake::Task.new do |t|
37
+ profile = ENV['PROFILE'] || 'default'
38
+ t.cucumber_opts = "--profile #{profile}"
39
+ end
40
+
41
+ YARD::Rake::YardocTask.new do |t|
42
+ t.files = ["README.md", "LICENSE", "TODO", 'lib/carrierwave/**/*.rb']
43
+ end
44
+
45
+ Rake::GemPackageTask.new(spec) do |pkg|
46
+ pkg.gem_spec = spec
47
+ end
48
+
49
+ desc "install the plugin locally"
50
+ task :install => [:package] do
51
+ sh %{#{sudo} gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION} --no-update-sources}
52
+ end
53
+
54
+ desc "create a gemspec file"
55
+ task :make_spec do
56
+ File.open("#{NAME}.gemspec", "w") do |file|
57
+ file.puts spec.to_ruby
58
+ end
59
+ end
60
+
61
+ namespace :jruby do
62
+
63
+ desc "Run :package and install the resulting .gem with jruby"
64
+ task :install => :package do
65
+ sh %{#{sudo} jruby -S gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION}.gem --no-rdoc --no-ri}
66
+ end
67
+
68
+ end
69
+
70
+ file_list = FileList['spec/**/*_spec.rb']
71
+
72
+ desc "Run all examples"
73
+ Spec::Rake::SpecTask.new('spec') do |t|
74
+ t.spec_files = file_list
75
+ end
76
+
77
+ namespace :spec do
78
+ desc "Run all examples with RCov"
79
+ Spec::Rake::SpecTask.new('rcov') do |t|
80
+ t.spec_files = file_list
81
+ t.rcov = true
82
+ t.rcov_dir = "doc/coverage"
83
+ t.rcov_opts = ['--exclude', 'spec']
84
+ end
85
+
86
+ desc "Generate an html report"
87
+ Spec::Rake::SpecTask.new('report') do |t|
88
+ t.spec_files = file_list
89
+ t.spec_opts = ["--format", "html:doc/reports/specs.html"]
90
+ t.fail_on_error = false
91
+ end
92
+
93
+ end
94
+
95
+ desc 'Default: run unit tests.'
96
+ task :default => 'spec'
data/TODO ADDED
File without changes
@@ -0,0 +1,67 @@
1
+ require 'fileutils'
2
+
3
+ module CarrierWave
4
+ class << self
5
+ attr_accessor :config
6
+ end
7
+
8
+ class UploadError < StandardError; end
9
+ class NoFileError < UploadError; end
10
+ class FormNotMultipart < UploadError
11
+ def message
12
+ "You tried to assign a String or a Pathname to an uploader, for security reasons, this is not allowed.\n\n If this is a file upload, please check that your upload form is multipart encoded."
13
+ end
14
+ end
15
+ class InvalidParameter < UploadError; end
16
+ # Should be used by methods used as process callbacks.
17
+ class ProcessingError < UploadError; end
18
+ end
19
+
20
+ dir = File.join(File.dirname(__FILE__), 'carrierwave')
21
+
22
+ require File.join(dir, 'sanitized_file')
23
+ require File.join(dir, 'uploader')
24
+ require File.join(dir, 'mount')
25
+ require File.join(dir, 'storage', 'abstract')
26
+ require File.join(dir, 'storage', 'file')
27
+ require File.join(dir, 'storage', 's3')
28
+
29
+ CarrierWave.config = {
30
+ :storage => :file,
31
+ :use_cache => true,
32
+ :storage_engines => {
33
+ :file => CarrierWave::Storage::File,
34
+ :s3 => CarrierWave::Storage::S3
35
+ },
36
+ :s3 => {
37
+ :access => :public_read
38
+ },
39
+ :store_dir => 'uploads',
40
+ :cache_dir => 'uploads/tmp'
41
+ }
42
+
43
+ if defined?(Merb)
44
+ CarrierWave.config[:root] = Merb.root
45
+ CarrierWave.config[:public] = Merb.dir_for(:public)
46
+
47
+ orm_path = File.dirname(__FILE__) / 'carrierwave' / 'orm' / Merb.orm
48
+ require orm_path if File.exist?(orm_path + '.rb')
49
+
50
+ Merb.push_path(:uploader, Merb.root / "app" / "uploaders")
51
+
52
+ Merb.add_generators File.dirname(__FILE__) / 'generators' / 'uploader_generator'
53
+ end
54
+
55
+ if defined?(Rails)
56
+ CarrierWave.config[:root] = Rails.root
57
+ CarrierWave.config[:public] = File.join(Rails.root, 'public')
58
+
59
+ require File.join(File.dirname(__FILE__), "carrierwave", "orm", 'activerecord')
60
+
61
+ ActiveSupport::Dependencies.load_paths << File.join(Rails.root, "app", "uploaders")
62
+ end
63
+
64
+ if defined?(Sinatra)
65
+ CarrierWave.config[:root] = Sinatra::Application.root
66
+ CarrierWave.config[:public] = Sinatra::Application.public
67
+ end
@@ -0,0 +1,153 @@
1
+ module CarrierWave
2
+
3
+ ##
4
+ # If a Class is extended with this module, it gains the mount_uploader
5
+ # method, which is used for mapping attributes to uploaders and allowing
6
+ # easy assignment.
7
+ #
8
+ # You can use mount_uploader with pretty much any class, however it is
9
+ # intended to be used with some kind of persistent storage, like an ORM.
10
+ # If you want to persist the uploaded files in a particular Class, it
11
+ # needs to implement a `read_uploader` and a `write_uploader` method.
12
+ #
13
+ module Mount
14
+
15
+ ##
16
+ # @return [Hash{Symbol => CarrierWave}] what uploaders are mounted on which columns
17
+ #
18
+ def uploaders
19
+ @uploaders ||= {}
20
+ end
21
+
22
+ ##
23
+ # Mounts the given uploader on the given column. This means that assigning
24
+ # and reading from the column will upload and retrieve files. Supposing
25
+ # that a User class has an uploader mounted on image, you can assign and
26
+ # retrieve files like this:
27
+ #
28
+ # @user.image # => <Uploader>
29
+ # @user.image = some_file_object
30
+ #
31
+ # @user.store_image!
32
+ #
33
+ # @user.image.url # => '/some_url.png'
34
+ #
35
+ # It is also possible (but not recommended) to ommit the uploader, which
36
+ # will create an anonymous uploader class. Passing a block to this method
37
+ # makes it possible to customize it. This can be convenient for brevity,
38
+ # but if there is any significatnt logic in the uploader, you should do
39
+ # the right thing and have it in its own file.
40
+ #
41
+ # @param [Symbol] column the attribute to mount this uploader on
42
+ # @param [CarrierWave::Uploader] uploader the uploader class to mount
43
+ # @param [Proc] &block customize anonymous uploaders
44
+ # @example
45
+ # class Song
46
+ # mount_uploader :lyrics, LyricsUploader
47
+ # mount_uploader :file, SongUploader
48
+ # end
49
+ # @example
50
+ # class Data
51
+ # # this will add an anonymous uploader with only
52
+ # # the default settings
53
+ # mount_uploader :csv
54
+ # end
55
+ # @example
56
+ # class Product
57
+ # # this will add an anonymous uploader overriding
58
+ # # the store_dir
59
+ # mount_uploader :blueprint do
60
+ # def store_dir
61
+ # 'blueprints'
62
+ # end
63
+ # end
64
+ # end
65
+ #
66
+ def mount_uploader(column, uploader=nil, &block)
67
+ unless uploader
68
+ uploader = Class.new(CarrierWave::Uploader)
69
+ uploader.class_eval(&block)
70
+ end
71
+
72
+ uploaders[column.to_sym] = uploader
73
+
74
+ include CarrierWave::Mount::Extension
75
+
76
+ class_eval <<-EOF, __FILE__, __LINE__+1
77
+ def #{column} # def image
78
+ get_uploader(:#{column}) # get_uploader(:image)
79
+ end # end
80
+ #
81
+ def #{column}=(new_file) # def image=(new_file)
82
+ set_uploader(:#{column}, new_file) # set_uploader(:image, new_file)
83
+ end # end
84
+ #
85
+ def #{column}_cache # def image_cache
86
+ get_uploader_cache(:#{column}) # get_uploader_cache(:image)
87
+ end # end
88
+ #
89
+ def #{column}_cache=(cache_name) # def image_cache=(cache_name)
90
+ set_uploader_cache(:#{column}, cache_name) # set_uploader_cache(:image, cache_name)
91
+ end # end
92
+ #
93
+ def store_#{column}! # def store_image!
94
+ store_uploader!(:#{column}) # store_uploader!(:image)
95
+ end # end
96
+ EOF
97
+
98
+ after_mount(column, uploader) if respond_to?(:after_mount)
99
+ end
100
+
101
+ module Extension
102
+
103
+ private
104
+
105
+ # overwrite this to read from a serialized attribute
106
+ def read_uploader(column); end
107
+
108
+ # overwrite this to write to a serialized attribute
109
+ def write_uploader(column, identifier); end
110
+
111
+ def uploaders
112
+ @uploaders ||= {}
113
+ end
114
+
115
+ def store_uploader!(column)
116
+ unless uploaders[column].blank?
117
+ uploaders[column].store!
118
+ write_uploader(column, uploaders[column].identifier)
119
+ end
120
+ end
121
+
122
+ def get_uploader(column)
123
+ return uploaders[column] unless uploaders[column].blank?
124
+
125
+ identifier = read_uploader(column)
126
+
127
+ unless identifier.blank?
128
+ uploaders[column] ||= self.class.uploaders[column].new(self, column)
129
+ uploaders[column].retrieve_from_store!(identifier)
130
+ uploaders[column]
131
+ end
132
+ end
133
+
134
+ def set_uploader(column, new_file)
135
+ uploaders[column] ||= self.class.uploaders[column].new(self, column)
136
+ uploaders[column].cache!(new_file)
137
+ end
138
+
139
+ def get_uploader_cache(column)
140
+ uploaders[column].cache_name unless uploaders[column].blank?
141
+ end
142
+
143
+ def set_uploader_cache(column, cache_name)
144
+ unless cache_name.blank?
145
+ uploaders[column] ||= self.class.uploaders[column].new(self, column)
146
+ uploaders[column].retrieve_from_cache(cache_name)
147
+ end
148
+ end
149
+
150
+ end # Extension
151
+
152
+ end # Mount
153
+ end # CarrierWave