glebtv-carrierwave-mongoid 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b123e28179c988419a4b691e9ef8a7a5c28561c0
4
+ data.tar.gz: 8a80da6aadf2c2c22515575d9198d1b76ed348e6
5
+ SHA512:
6
+ metadata.gz: 1807b69bd7c9cb3eabd0f2ba04d440aafeb5aadbc5a314cf70f7e3479d22c4f092d09710e425b442b4425e214ea8e69611695ed3ee45cf49097565bb2eb52e9c
7
+ data.tar.gz: 990e56ff5543e2749247c1aca0783a5a8a18bd5d787d0957df91db9bfb07a937d9901d642b316bc99e1de9708df0c88b6bb4b3a99566f1ebb9db6ab329e2993e
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ pkg/*
2
+ *.gem
3
+ *.sw*
4
+ .bundle
5
+ spec/public
6
+ .rvmrc
7
+ .ruby-version
8
+ Gemfile.lock
9
+ gemfiles/*.lock
10
+ log/*
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ glebtv-carrierwave-mongoid
data/.travis.yml ADDED
@@ -0,0 +1,18 @@
1
+ services: mongodb
2
+
3
+ notifications:
4
+ email: false
5
+
6
+ language: ruby
7
+ rvm:
8
+ - 1.9.3
9
+ - 2.0.0
10
+ - jruby-19mode
11
+ - rbx-19mode
12
+
13
+ gemfile:
14
+ - Gemfile
15
+ - gemfiles/carrierwave-master.gemfile
16
+ - gemfiles/mongoid-3.0.gemfile
17
+ - gemfiles/mongoid-3.1.gemfile
18
+ - gemfiles/mongoid-4.0.gemfile
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in glebtv-carrierwave-mongoid.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008-2012 Jonas Nicklas
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.md ADDED
@@ -0,0 +1,5 @@
1
+ # Fork with OPTIONAL gridfs
2
+
3
+ # CarrierWave for Mongoid
4
+
5
+ See upstream for details: https://github.com/carrierwaveuploader/carrierwave-mongoid
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler/setup'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc "Run all examples"
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ #t.rspec_path = 'bin/rspec'
9
+ t.rspec_opts = %w[--color]
10
+ end
11
+
12
+ task :default => :spec
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "carrierwave", github: "carrierwaveuploader/carrierwave", branch: "master"
4
+
5
+ gemspec path: "../"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mongoid", github: "mongoid/mongoid", branch: "3.0.0-stable"
4
+
5
+ gemspec path: "../"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mongoid", github: "mongoid/mongoid", branch: "3.1.0-stable"
4
+
5
+ gemspec path: "../"
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "mongoid-grid_fs", github: "ahoward/mongoid-grid_fs", branch: "master"
4
+ gem "mongoid", github: "mongoid/mongoid", branch: "master"
5
+
6
+ gemspec path: "../"
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "carrierwave/mongoid/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "glebtv-carrierwave-mongoid"
7
+ s.version = Carrierwave::Mongoid::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["GlebTv", "Jonas Nicklas", "Trevor Turk"]
10
+ s.email = ["jonas.nicklas@gmail.com"]
11
+ s.homepage = "https://github.com/crowdtask/carrierwave-mongoid"
12
+ s.summary = %q{This fork makes GridFS optional}
13
+ s.description = %q{This fork makes GridFS optional}
14
+ s.license = "MIT"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "carrierwave", ["~> 0.8.0"]
22
+ s.add_dependency "mongoid", [">= 3.0", "< 5.0"]
23
+ s.add_development_dependency "rspec", ["~> 2.6"]
24
+ s.add_development_dependency "rake", ["~> 10.0"]
25
+ s.add_development_dependency "mini_magick"
26
+ s.add_development_dependency "pry"
27
+ end
@@ -0,0 +1,101 @@
1
+ # encoding: utf-8
2
+
3
+ require 'mongoid'
4
+ require 'carrierwave'
5
+ require 'carrierwave/validations/active_model'
6
+
7
+ module CarrierWave
8
+ module Mongoid
9
+ include CarrierWave::Mount
10
+ ##
11
+ # See +CarrierWave::Mount#mount_uploader+ for documentation
12
+ #
13
+ def mount_uploader(column, uploader=nil, options={}, &block)
14
+ field options[:mount_on] || column
15
+
16
+ super
17
+
18
+ alias_method :read_uploader, :read_attribute
19
+ alias_method :write_uploader, :write_attribute
20
+ public :read_uploader
21
+ public :write_uploader
22
+
23
+ include CarrierWave::Validations::ActiveModel
24
+
25
+ validates_integrity_of column if uploader_option(column.to_sym, :validate_integrity)
26
+ validates_processing_of column if uploader_option(column.to_sym, :validate_processing)
27
+
28
+ after_save :"store_#{column}!"
29
+ before_save :"write_#{column}_identifier"
30
+ after_destroy :"remove_#{column}!"
31
+ before_update :"store_previous_model_for_#{column}"
32
+ after_save :"remove_previously_stored_#{column}"
33
+
34
+ class_eval <<-RUBY, __FILE__, __LINE__+1
35
+ def #{column}=(new_file)
36
+ column = _mounter(:#{column}).serialization_column
37
+
38
+ # mongoid won't upload a new file if there was no file previously.
39
+ write_uploader(column, '_old_') if self.persisted? && read_uploader(column).nil?
40
+
41
+ send(:"\#{column}_will_change!")
42
+ super
43
+ end
44
+
45
+ def remove_#{column}!
46
+ super unless respond_to?(:paranoid?) && paranoid? && flagged_for_destroy?
47
+ end
48
+
49
+ # Overrides Mongoid's default dirty behavior to instead work more like
50
+ # ActiveRecord's. Mongoid doesn't deem an attribute as changed unless
51
+ # the new value is different than the original. Given that CarrierWave
52
+ # caches files before save, it's necessary to know that there's a
53
+ # pending change even though the attribute value itself might not
54
+ # reflect that yet.
55
+ def #{column}_changed?
56
+ changed_attributes.has_key?("#{column}")
57
+ end
58
+
59
+ def find_previous_model_for_#{column}
60
+ if self.embedded?
61
+ ancestors = [[ self.metadata.key, self._parent ]].tap { |x| x.unshift([ x.first.last.metadata.key, x.first.last._parent ]) while x.first.last.embedded? }
62
+ first_parent = ancestors.first.last
63
+ reloaded_parent = first_parent.class.unscoped.find(first_parent.to_key.first)
64
+ association = ancestors.inject(reloaded_parent) { |parent,(key,ancestor)| (parent.is_a?(Array) ? parent.find(ancestor.to_key.first) : parent).send(key) }
65
+ association.is_a?(Array) ? association.find(to_key.first) : association
66
+ else
67
+ self.class.unscoped.for_ids(to_key).first
68
+ end
69
+ end
70
+
71
+ def serializable_hash(options=nil)
72
+ hash = {}
73
+
74
+ except = options && options[:except] && Array.wrap(options[:except]).map(&:to_s)
75
+ only = options && options[:only] && Array.wrap(options[:only]).map(&:to_s)
76
+
77
+ self.class.uploaders.each do |column, uploader|
78
+ if (!only && !except) || (only && only.include?(column.to_s)) || (except && !except.include?(column.to_s))
79
+ hash[column.to_s] = _mounter(column.to_sym).uploader.serializable_hash
80
+ end
81
+ end
82
+ super(options).merge(hash)
83
+ end
84
+ RUBY
85
+ end
86
+ end # Mongoid
87
+ end # CarrierWave
88
+
89
+ if defined?(Mongoid::GridFs)
90
+ CarrierWave::Storage.autoload :GridFS, 'carrierwave/storage/grid_fs'
91
+
92
+ class CarrierWave::Uploader::Base
93
+ add_config :grid_fs_access_url
94
+
95
+ configure do |config|
96
+ config.storage_engines[:grid_fs] = "CarrierWave::Storage::GridFS"
97
+ end
98
+ end
99
+ end
100
+
101
+ Mongoid::Document::ClassMethods.send(:include, CarrierWave::Mongoid)
@@ -0,0 +1,5 @@
1
+ module Carrierwave
2
+ module Mongoid
3
+ VERSION = "0.6.0"
4
+ end
5
+ end
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+
3
+ module CarrierWave
4
+ module Storage
5
+
6
+ ##
7
+ # The GridFS store uses MongoDB's GridStore file storage system to store files
8
+ #
9
+ # When you already have a Mongo connection object (for example through Mongoid)
10
+ # you can also reuse this connection:
11
+ #
12
+ # CarrierWave.configure do |config|
13
+ # config.storage = :grid_fs
14
+ # config.grid_fs_access_url = "/system/uploads"
15
+ # end
16
+ #
17
+ # In the above example your documents url will look like:
18
+ #
19
+ # http://your-app.com/system/uploads/:document-identifier-here
20
+ #
21
+ class GridFS < Abstract
22
+
23
+ class File
24
+ attr_reader :path
25
+ attr_reader :uploader
26
+ attr_reader :grid_file
27
+
28
+ def initialize(uploader, path)
29
+ @path = path
30
+ @uploader = uploader
31
+ @grid_file = nil
32
+ end
33
+
34
+ def url
35
+ unless @uploader.grid_fs_access_url
36
+ nil
37
+ else
38
+ ::File.join(@uploader.grid_fs_access_url, path)
39
+ end
40
+ end
41
+
42
+ def grid_file(&block)
43
+ @grid_file ||= grid[path]
44
+ end
45
+
46
+ def write(file)
47
+ grid[@uploader.store_path] = file
48
+ ensure
49
+ @grid_file = nil
50
+ end
51
+
52
+ def read
53
+ grid_file.data if grid_file
54
+ end
55
+
56
+ %w( delete content_type length ).each do |method|
57
+ class_eval <<-__, __FILE__, __LINE__
58
+ def #{ method }
59
+ grid_file.#{ method } if grid_file
60
+ end
61
+ __
62
+ end
63
+
64
+ alias :content_length :length
65
+ alias :file_length :length
66
+ alias :size :length
67
+
68
+ protected
69
+ class << File
70
+ attr_accessor :grid
71
+ end
72
+
73
+ self.grid = ::Mongoid::GridFS
74
+
75
+ def grid
76
+ self.class.grid
77
+ end
78
+ end # File
79
+
80
+ ##
81
+ # Store the file in MongoDB's GridFS GridStore
82
+ #
83
+ # === Parameters
84
+ #
85
+ # [file (CarrierWave::SanitizedFile)] the file to store
86
+ #
87
+ # === Returns
88
+ #
89
+ # [CarrierWave::SanitizedFile] a sanitized file
90
+ #
91
+ def store!(file)
92
+ stored = CarrierWave::Storage::GridFS::File.new(uploader, uploader.store_path)
93
+ stored.write(file)
94
+ stored
95
+ end
96
+
97
+ ##
98
+ # Retrieve the file from MongoDB's GridFS GridStore
99
+ #
100
+ # === Parameters
101
+ #
102
+ # [identifier (String)] the filename of the file
103
+ #
104
+ # === Returns
105
+ #
106
+ # [CarrierWave::Storage::GridFS::File] a sanitized file
107
+ #
108
+ def retrieve!(identifier)
109
+ CarrierWave::Storage::GridFS::File.new(uploader, uploader.store_path(identifier))
110
+ end
111
+
112
+ end # GridFS
113
+ end # Storage
114
+ end # CarrierWave
@@ -0,0 +1 @@
1
+ require 'carrierwave/mongoid'
@@ -0,0 +1 @@
1
+ this is stuff
@@ -0,0 +1 @@
1
+ bork bork bork Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
@@ -0,0 +1 @@
1
+ this is stuff
@@ -0,0 +1 @@
1
+ bork bork bork Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Binary file
@@ -0,0 +1 @@
1
+ this is stuff
@@ -0,0 +1 @@
1
+ this is stuff
@@ -0,0 +1,834 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ require 'carrierwave/mongoid'
5
+
6
+ def reset_mongo_class(uploader = MongoUploader)
7
+ define_mongo_class('MongoUser') do
8
+ include Mongoid::Document
9
+ store_in :collection => 'users'
10
+ field :folder, :default => ''
11
+ mount_uploader :image, uploader
12
+ end
13
+ end
14
+
15
+ def define_mongo_class(class_name, &block)
16
+ Object.send(:remove_const, class_name) rescue nil
17
+ klass = Object.const_set(class_name, Class.new)
18
+ klass.class_eval(&block)
19
+ klass
20
+ end
21
+
22
+ class MongoUploader < CarrierWave::Uploader::Base; end
23
+ class AnotherMongoUploader < CarrierWave::Uploader::Base; end
24
+
25
+ class IntegrityErrorUploader < CarrierWave::Uploader::Base
26
+ process :monkey
27
+ def monkey
28
+ raise CarrierWave::IntegrityError
29
+ end
30
+ def extension_white_list
31
+ %w(jpg)
32
+ end
33
+ end
34
+
35
+ class ProcessingErrorUploader < CarrierWave::Uploader::Base
36
+ process :monkey
37
+ def monkey
38
+ raise CarrierWave::ProcessingError
39
+ end
40
+ def extension_white_list
41
+ %w(jpg)
42
+ end
43
+ end
44
+
45
+
46
+ describe CarrierWave::Mongoid do
47
+
48
+ after do
49
+ MongoUser.collection.drop if MongoUser.count > 0
50
+ end
51
+
52
+ describe '#image' do
53
+
54
+ context "when nothing is assigned" do
55
+
56
+ before do
57
+ mongo_user_klass = reset_mongo_class
58
+ @document = mongo_user_klass.new
59
+ end
60
+
61
+ it "returns a blank uploader" do
62
+ @document.image.should be_blank
63
+ end
64
+
65
+ end
66
+
67
+ context "when an empty string is assigned" do
68
+
69
+ before do
70
+ mongo_user_klass = reset_mongo_class
71
+ @document = mongo_user_klass.new(:image => "")
72
+ @document.save
73
+ end
74
+
75
+ it "returns a blank uploader" do
76
+ @saved_doc = MongoUser.first
77
+ @saved_doc.image.should be_blank
78
+ end
79
+
80
+ end
81
+
82
+ context "when a filename is saved in the database" do
83
+
84
+ before do
85
+ mongo_user_klass = reset_mongo_class
86
+ @document = mongo_user_klass.new
87
+ # should retrieve a file from the storage if a value is stored in the database
88
+ @document[:image] = "test.jpg" # NOT @document.image = 'text.jpg'
89
+ @document.save
90
+ @doc = MongoUser.first
91
+ end
92
+
93
+ it "returns an uploader" do
94
+ @doc.image.should be_an_instance_of(MongoUploader)
95
+ end
96
+
97
+ it "sets the path to the store directory" do
98
+ @doc.image.current_path.should == public_path('uploads/test.jpg')
99
+ end
100
+
101
+ it "should return valid JSON when to_json is called when image is nil" do
102
+ @doc[:image] = nil
103
+ hash = JSON.parse(@doc.to_json)
104
+ hash.keys.should include("image")
105
+ hash["image"].keys.should include("url")
106
+ hash["image"]["url"].should be_nil
107
+ end
108
+
109
+ it "should return valid JSON when to_json is called when image is present" do
110
+ @doc[:image] = 'test.jpeg'
111
+ @doc.save!
112
+ @doc.reload
113
+
114
+ JSON.parse(@doc.to_json)["image"].should == {"url" => "/uploads/test.jpeg"}
115
+ end
116
+
117
+ it "should return valid JSON when to_json is called on a collection containing uploader from a model" do
118
+ @doc[:image] = 'test.jpeg'
119
+ @doc.save!
120
+ @doc.reload
121
+
122
+ JSON.parse({:data => @doc.image}.to_json).should == {"data"=>{"image"=>{"url"=>"/uploads/test.jpeg"}}}
123
+ end
124
+
125
+ it "should respect options[:only] when passed to to_json for the serializable hash" do
126
+ @doc[:image] = 'test.jpeg'
127
+ @doc.save!
128
+ @doc.reload
129
+ JSON.parse(@doc.to_json({:only => [:_id]})).should == {"_id" => @doc.id.as_json}
130
+ end
131
+
132
+ it "should respect options[:except] when passed to to_json for the serializable hash" do
133
+ @doc[:image] = 'test.jpeg'
134
+ @doc.save!
135
+ @doc.reload
136
+
137
+ JSON.parse(@doc.to_json({:except => [:_id, :image]})).should == {"folder" => ""}
138
+ end
139
+
140
+ end
141
+
142
+ end
143
+
144
+ describe '#image=' do
145
+
146
+ before do
147
+ mongo_user_klass = reset_mongo_class
148
+ @doc = mongo_user_klass.new
149
+ end
150
+
151
+ context "when nil is assigned" do
152
+
153
+ it "does not set the value" do
154
+ @doc.image = nil
155
+ @doc.image.should be_blank
156
+ end
157
+
158
+ end
159
+
160
+ context "when an empty string is assigned" do
161
+
162
+ it "does not set the value" do
163
+ @doc.image = ''
164
+ @doc.image.should be_blank
165
+ end
166
+
167
+ end
168
+
169
+ context "when a file is assigned" do
170
+
171
+ it "should cache a file" do
172
+ @doc.image = stub_file('test.jpeg')
173
+ @doc.image.should be_an_instance_of(MongoUploader)
174
+ end
175
+
176
+ it "should write nothing to the database, to prevent overriden filenames to fail because of unassigned attributes" do
177
+ @doc[:image].should be_nil
178
+ end
179
+
180
+ it "should copy a file into into the cache directory" do
181
+ @doc.image = stub_file('test.jpeg')
182
+ @doc.image.current_path.should =~ /^#{public_path('uploads\/tmp')}/
183
+ end
184
+
185
+ end
186
+
187
+ context 'when validating integrity' do
188
+ before do
189
+ mongo_user_klass = reset_mongo_class(IntegrityErrorUploader)
190
+ @doc = mongo_user_klass.new
191
+ @doc.image = stub_file('test.jpg')
192
+ end
193
+
194
+ it "should make the document invalid when an integrity error occurs" do
195
+ @doc.should_not be_valid
196
+ end
197
+
198
+ it "should use I18n for integrity error messages" do
199
+ @doc.valid?
200
+ @doc.errors[:image].should == ['is not of an allowed file type']
201
+
202
+ change_locale_and_store_translations(:pt, :mongoid => {
203
+ :errors => {
204
+ :messages => {
205
+ :carrierwave_integrity_error => 'tipo de imagem não permitido.'
206
+ }
207
+ }
208
+ }) do
209
+ @doc.should_not be_valid
210
+ @doc.errors[:image].should == ['tipo de imagem não permitido.']
211
+ end
212
+ end
213
+ end
214
+
215
+ context 'when validating processing' do
216
+ before do
217
+ mongo_user_klass = reset_mongo_class(ProcessingErrorUploader)
218
+ @doc = mongo_user_klass.new
219
+ @doc.image = stub_file('test.jpg')
220
+ end
221
+
222
+ it "should make the document invalid when a processing error occurs" do
223
+ @doc.should_not be_valid
224
+ end
225
+
226
+ it "should use I18n for processing error messages" do
227
+ @doc.valid?
228
+ @doc.errors[:image].should == ['failed to be processed']
229
+
230
+ change_locale_and_store_translations(:pt, :mongoid => {
231
+ :errors => {
232
+ :messages => {
233
+ :carrierwave_processing_error => 'falha ao processar imagem.'
234
+ }
235
+ }
236
+ }) do
237
+ @doc.should_not be_valid
238
+ @doc.errors[:image].should == ['falha ao processar imagem.']
239
+ end
240
+ end
241
+ end
242
+
243
+ end
244
+
245
+ describe "#save" do
246
+
247
+ it "after it was initialized with params" do
248
+ doc = reset_mongo_class.new(:image => stub_file('test.jpg'))
249
+ doc.save.should be_true
250
+ doc.image.should be_an_instance_of(MongoUploader)
251
+ doc.image.current_path.should == public_path('uploads/test.jpg')
252
+ end
253
+
254
+ before do
255
+ mongo_user_klass = reset_mongo_class
256
+ @doc = mongo_user_klass.new
257
+ end
258
+
259
+ context "when no file is assigned" do
260
+
261
+ it "image is blank" do
262
+ @doc.save.should be_true
263
+ @doc.image.should be_blank
264
+ end
265
+
266
+ end
267
+
268
+ context "when a file is assigned" do
269
+
270
+ it "copies the file to the upload directory" do
271
+ @doc.image = stub_file('test.jpg')
272
+ @doc.save.should be_true
273
+ @doc.image.should be_an_instance_of(MongoUploader)
274
+ @doc.image.current_path.should == public_path('uploads/test.jpg')
275
+ end
276
+
277
+ it "saves the filename in the database" do
278
+ @doc.image = stub_file('test.jpg')
279
+ @doc.save.should be_true
280
+ @doc[:image].should == 'test.jpg'
281
+ @doc.image_identifier.should == 'test.jpg'
282
+ end
283
+
284
+ context "when remove_image? is true" do
285
+
286
+ it "removes the image" do
287
+ @doc.image = stub_file('test.jpeg')
288
+ @doc.save
289
+ @doc.remove_image = true
290
+ @doc.save.should be_true
291
+ @doc.reload
292
+ @doc.image.should be_blank
293
+ @doc.image_identifier.should == ''
294
+ end
295
+
296
+ end
297
+
298
+ it "should mark image as changed when saving a new image" do
299
+ @doc.image_changed?.should be_false
300
+ @doc.image = stub_file("test.jpeg")
301
+ @doc.image_changed?.should be_true
302
+ @doc.save
303
+ @doc.reload
304
+ @doc.image_changed?.should be_false
305
+ @doc.image = stub_file("test.jpg")
306
+ @doc.image_changed?.should be_true
307
+ end
308
+
309
+ end
310
+
311
+ end
312
+
313
+ describe '#update' do
314
+
315
+ before do
316
+ mongo_user_klass = reset_mongo_class
317
+ @doc = mongo_user_klass.new
318
+ @doc.image = stub_file('test.jpeg')
319
+ @doc.save
320
+ @doc.reload
321
+ end
322
+
323
+ it "replaced it by a file with the same name" do
324
+ @doc.image = stub_file('test.jpeg')
325
+ @doc.save
326
+ @doc.reload
327
+ @doc[:image].should == 'test.jpeg'
328
+ @doc.image_identifier.should == 'test.jpeg'
329
+ end
330
+
331
+ end
332
+
333
+ describe '#destroy' do
334
+
335
+ before do
336
+ mongo_user_klass = reset_mongo_class
337
+ @doc = mongo_user_klass.new
338
+ end
339
+
340
+ describe "when file assigned" do
341
+
342
+ it "removes the file from the filesystem" do
343
+ @doc.image = stub_file('test.jpeg')
344
+ @doc.save.should be_true
345
+ File.exist?(public_path('uploads/test.jpeg')).should be_true
346
+ @doc.image.should be_an_instance_of(MongoUploader)
347
+ @doc.image.current_path.should == public_path('uploads/test.jpeg')
348
+ @doc.destroy
349
+ File.exist?(public_path('uploads/test.jpeg')).should be_false
350
+ end
351
+
352
+ end
353
+
354
+ describe "when file is not assigned" do
355
+
356
+ it "deletes the instance of MongoUser after save" do
357
+ @doc.save
358
+ MongoUser.count.should eql(1)
359
+ @doc.destroy
360
+ end
361
+
362
+ it "deletes the instance of MongoUser after save and then re-looking up the instance" do
363
+ @doc.save
364
+ MongoUser.count.should eql(1)
365
+ @doc = MongoUser.first
366
+ @doc.destroy
367
+ end
368
+
369
+ end
370
+
371
+ end
372
+
373
+ describe '#mount_uploader removing old files' do
374
+
375
+ before do
376
+ @uploader = Class.new(MongoUploader)
377
+ @class = reset_mongo_class(@uploader)
378
+ @class.field :foo
379
+ @doc = @class.new
380
+ @doc.image = stub_file('old.jpeg')
381
+ @doc.save.should be_true
382
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
383
+ end
384
+
385
+ after do
386
+ FileUtils.rm_rf(file_path("uploads"))
387
+ end
388
+
389
+ describe 'normally' do
390
+
391
+ it "should remove old file if old file had a different path" do
392
+ @doc.image = stub_file('new.jpeg')
393
+ @doc.save.should be_true
394
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
395
+ File.exists?(public_path('uploads/old.jpeg')).should be_false
396
+ end
397
+
398
+ it "should not remove old file if old file had a different path but config is false" do
399
+ @uploader.stub!(:remove_previously_stored_files_after_update).and_return(false)
400
+ @doc.image = stub_file('new.jpeg')
401
+ @doc.save.should be_true
402
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
403
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
404
+ end
405
+
406
+ it "should not remove file if old file had the same path" do
407
+ @doc.image = stub_file('old.jpeg')
408
+ @doc.save.should be_true
409
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
410
+ end
411
+
412
+ it "should not remove file if validations fail on save" do
413
+ @class.validate { |r| r.errors.add :textfile, "FAIL!" }
414
+ @doc.image = stub_file('new.jpeg')
415
+ @doc.save.should be_false
416
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
417
+ end
418
+ end
419
+
420
+ describe 'with an overriden filename' do
421
+ before do
422
+ @uploader.class_eval do
423
+ def filename
424
+ model.foo + File.extname(super)
425
+ end
426
+ end
427
+
428
+ @doc.image = stub_file('old.jpeg')
429
+ @doc.foo = "test"
430
+ @doc.save.should be_true
431
+ File.exists?(public_path('uploads/test.jpeg')).should be_true
432
+ @doc.image.read.should == "this is stuff"
433
+ end
434
+
435
+ it "should not remove file if old file had the same dynamic path" do
436
+ @doc.image = stub_file('test.jpeg')
437
+ @doc.save.should be_true
438
+ File.exists?(public_path('uploads/test.jpeg')).should be_true
439
+ end
440
+
441
+ it "should remove old file if old file had a different dynamic path" do
442
+ @doc.foo = "new"
443
+ @doc.image = stub_file('test.jpeg')
444
+ @doc.save.should be_true
445
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
446
+ File.exists?(public_path('uploads/test.jpeg')).should be_false
447
+ end
448
+ end
449
+
450
+ shared_examples "embedded documents" do
451
+ it "should remove old file if old file had a different path" do
452
+ @embedded_doc.image = stub_file('new.jpeg')
453
+ @embedded_doc.save.should be_true
454
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
455
+ File.exists?(public_path('uploads/old.jpeg')).should be_false
456
+ end
457
+
458
+ it "should not remove old file if old file had a different path but config is false" do
459
+ @embedded_doc.image.stub!(:remove_previously_stored_files_after_update).and_return(false)
460
+ @embedded_doc.image = stub_file('new.jpeg')
461
+ @embedded_doc.save.should be_true
462
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
463
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
464
+ end
465
+
466
+ it "should not remove file if old file had the same path" do
467
+ @embedded_doc.image = stub_file('old.jpeg')
468
+ @embedded_doc.save.should be_true
469
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
470
+ end
471
+
472
+ it "should not remove file if validations fail on save" do
473
+ @embedded_doc_class.validate { |r| r.errors.add :textfile, "FAIL!" }
474
+ @embedded_doc.image = stub_file('new.jpeg')
475
+ @embedded_doc.save.should be_false
476
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
477
+ end
478
+
479
+ it "should not touch parent's dirty attributes" do
480
+ @class.field :title
481
+ @doc.title = "Title"
482
+ @embedded_doc.image = stub_file('new.jpeg')
483
+ @embedded_doc.save.should be_true
484
+ @doc.title.should == "Title"
485
+ end
486
+ end
487
+
488
+ shared_examples "double embedded documents" do
489
+ it "should remove old file if old file had a different path" do
490
+ @double_embedded_doc.image = stub_file('new.jpeg')
491
+ @double_embedded_doc.save.should be_true
492
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
493
+ File.exists?(public_path('uploads/old.jpeg')).should be_false
494
+ end
495
+
496
+ it "should not remove old file if old file had a different path but config is false" do
497
+ @double_embedded_doc.image.stub!(:remove_previously_stored_files_after_update).and_return(false)
498
+ @double_embedded_doc.image = stub_file('new.jpeg')
499
+ @double_embedded_doc.save.should be_true
500
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
501
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
502
+ end
503
+
504
+ it "should not remove file if old file had the same path" do
505
+ @double_embedded_doc.image = stub_file('old.jpeg')
506
+ @double_embedded_doc.save.should be_true
507
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
508
+ end
509
+
510
+ it "should not remove file if validations fail on save" do
511
+ @double_embedded_doc_class.validate { |r| r.errors.add :textfile, "FAIL!" }
512
+ @double_embedded_doc.image = stub_file('new.jpeg')
513
+ @double_embedded_doc.save.should be_false
514
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
515
+ end
516
+
517
+ end
518
+
519
+ describe 'with document embedded as embeds_one' do
520
+ before do
521
+ @embedded_doc_class = define_mongo_class('MongoLocation') do
522
+ include Mongoid::Document
523
+ mount_uploader :image, @uploader
524
+ embedded_in :mongo_user
525
+ end
526
+
527
+ @class.class_eval do
528
+ embeds_one :mongo_location
529
+ end
530
+
531
+ @doc = @class.new
532
+ @embedded_doc = @doc.build_mongo_location
533
+ @embedded_doc.image = stub_file('old.jpeg')
534
+ @embedded_doc.save.should be_true
535
+ end
536
+
537
+ include_examples "embedded documents"
538
+ end
539
+
540
+ describe 'with document embedded as embeds_one and parent document not matched the default scope' do
541
+ before do
542
+ @embedded_doc_class = define_mongo_class('MongoLocation') do
543
+ include Mongoid::Document
544
+ mount_uploader :image, @uploader
545
+ embedded_in :mongo_user
546
+ end
547
+
548
+ @class.class_eval do
549
+ embeds_one :mongo_location
550
+ default_scope where(:always_false => false)
551
+ end
552
+
553
+ @doc = @class.new
554
+ @embedded_doc = @doc.build_mongo_location
555
+ @embedded_doc.image = stub_file('old.jpeg')
556
+ @embedded_doc.save.should be_true
557
+ end
558
+
559
+ include_examples "embedded documents"
560
+ end
561
+
562
+ describe 'with embedded documents' do
563
+ before do
564
+ @embedded_doc_class = define_mongo_class('MongoLocation') do
565
+ include Mongoid::Document
566
+ mount_uploader :image, @uploader
567
+ embedded_in :mongo_user
568
+ end
569
+
570
+ @class.class_eval do
571
+ embeds_many :mongo_locations, cascade_callbacks: true
572
+ end
573
+
574
+ @doc = @class.new
575
+ @embedded_doc = @doc.mongo_locations.build
576
+ @embedded_doc.image = stub_file('old.jpeg')
577
+ @embedded_doc.save.should be_true
578
+ end
579
+
580
+ include_examples "embedded documents"
581
+
582
+ it "attaches a new file to an existing document that had no file at first" do
583
+ doc = @class.new
584
+ doc.mongo_locations.build
585
+ doc.save.should be_true
586
+ doc.reload
587
+
588
+ doc.mongo_locations.first.image = stub_file('test.jpeg')
589
+ doc.save.should be_true
590
+ doc.reload
591
+
592
+ doc.mongo_locations.first[:image].should == 'test.jpeg'
593
+ end
594
+
595
+ describe 'with double embedded documents' do
596
+
597
+ before do
598
+ @double_embedded_doc_class = define_mongo_class('MongoItem') do
599
+ include Mongoid::Document
600
+ mount_uploader :image, @uploader
601
+ embedded_in :mongo_location
602
+ end
603
+
604
+ @embedded_doc_class.class_eval do
605
+ embeds_many :mongo_items
606
+ end
607
+
608
+ @doc = @class.new
609
+ @embedded_doc = @doc.mongo_locations.build
610
+ @embedded_doc.image = stub_file('old.jpeg')
611
+ @embedded_doc.save.should be_true
612
+
613
+ @double_embedded_doc = @embedded_doc.mongo_items.build
614
+ @double_embedded_doc.image = stub_file('old.jpeg')
615
+ @double_embedded_doc.save.should be_true
616
+ end
617
+
618
+ include_examples "double embedded documents"
619
+ end
620
+ end
621
+
622
+ describe 'with embedded documents and parent document not matched the default scope' do
623
+ before do
624
+ @embedded_doc_class = define_mongo_class('MongoLocation') do
625
+ include Mongoid::Document
626
+ mount_uploader :image, @uploader
627
+ embedded_in :mongo_user
628
+ end
629
+
630
+ @class.class_eval do
631
+ embeds_many :mongo_locations
632
+ default_scope where(:always_false => false)
633
+ end
634
+
635
+ @doc = @class.new
636
+ @embedded_doc = @doc.mongo_locations.build
637
+ @embedded_doc.image = stub_file('old.jpeg')
638
+ @embedded_doc.save.should be_true
639
+ end
640
+
641
+ include_examples "embedded documents"
642
+
643
+ describe 'with double embedded documents' do
644
+
645
+ before do
646
+ @double_embedded_doc_class = define_mongo_class('MongoItem') do
647
+ include Mongoid::Document
648
+ mount_uploader :image, @uploader
649
+ embedded_in :mongo_location
650
+ end
651
+
652
+ @embedded_doc_class.class_eval do
653
+ embeds_many :mongo_items
654
+ end
655
+
656
+ @doc = @class.new
657
+ @embedded_doc = @doc.mongo_locations.build
658
+ @embedded_doc.image = stub_file('old.jpeg')
659
+ @embedded_doc.save.should be_true
660
+
661
+ @double_embedded_doc = @embedded_doc.mongo_items.build
662
+ @double_embedded_doc.image = stub_file('old.jpeg')
663
+ @double_embedded_doc.save.should be_true
664
+ end
665
+
666
+ include_examples "double embedded documents"
667
+ end
668
+ end
669
+ end
670
+
671
+ describe '#mount_uploader removing old files with versions' do
672
+
673
+ before do
674
+ @uploader = Class.new(MongoUploader)
675
+ @uploader.version :thumb
676
+ @class = reset_mongo_class(@uploader)
677
+ @doc = @class.new
678
+ @doc.image = stub_file('old.jpeg')
679
+ @doc.save.should be_true
680
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
681
+ File.exists?(public_path('uploads/thumb_old.jpeg')).should be_true
682
+ end
683
+
684
+ after do
685
+ FileUtils.rm_rf(file_path("uploads"))
686
+ end
687
+
688
+ it "should remove old file if old file had a different path" do
689
+ @doc.image = stub_file('new.jpeg')
690
+ @doc.save.should be_true
691
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
692
+ File.exists?(public_path('uploads/thumb_new.jpeg')).should be_true
693
+ File.exists?(public_path('uploads/old.jpeg')).should be_false
694
+ File.exists?(public_path('uploads/thumb_old.jpeg')).should be_false
695
+ end
696
+
697
+ it "should not remove file if old file had the same path" do
698
+ @doc.image = stub_file('old.jpeg')
699
+ @doc.save.should be_true
700
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
701
+ File.exists?(public_path('uploads/thumb_old.jpeg')).should be_true
702
+ end
703
+ end
704
+
705
+ describe '#mount_uploader removing old files with multiple uploaders' do
706
+
707
+ before do
708
+ @uploader = Class.new(MongoUploader)
709
+ @class = reset_mongo_class(@uploader)
710
+ @uploader1 = Class.new(CarrierWave::Uploader::Base)
711
+ @class.mount_uploader(:textfile, @uploader1)
712
+ @doc = @class.new
713
+ @doc.image = stub_file('old.jpeg')
714
+ @doc.textfile = stub_file('old.txt')
715
+ @doc.save.should be_true
716
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
717
+ File.exists?(public_path('uploads/old.txt')).should be_true
718
+ end
719
+
720
+ after do
721
+ FileUtils.rm_rf(file_path("uploads"))
722
+ end
723
+
724
+ it "should remove old file1 and file2 if old file1 and file2 had a different paths" do
725
+ @doc.image = stub_file('new.jpeg')
726
+ @doc.textfile = stub_file('new.txt')
727
+ @doc.save.should be_true
728
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
729
+ File.exists?(public_path('uploads/old.jpeg')).should be_false
730
+ File.exists?(public_path('uploads/new.txt')).should be_true
731
+ File.exists?(public_path('uploads/old.txt')).should be_false
732
+ end
733
+
734
+ it "should remove old file1 but not file2 if old file1 had a different path but old file2 has the same path" do
735
+ @doc.image = stub_file('new.jpeg')
736
+ @doc.textfile = stub_file('old.txt')
737
+ @doc.save.should be_true
738
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
739
+ File.exists?(public_path('uploads/old.jpeg')).should be_false
740
+ File.exists?(public_path('uploads/old.txt')).should be_true
741
+ end
742
+
743
+ it "should not remove file1 or file2 if file1 and file2 have the same paths" do
744
+ @doc.image = stub_file('old.jpeg')
745
+ @doc.textfile = stub_file('old.txt')
746
+ @doc.save.should be_true
747
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
748
+ File.exists?(public_path('uploads/old.txt')).should be_true
749
+ end
750
+ end
751
+
752
+ describe '#mount_uploader removing old files with with mount_on' do
753
+
754
+ before do
755
+ @class = reset_mongo_class
756
+ @uploader1 = Class.new(CarrierWave::Uploader::Base)
757
+ @class.mount_uploader(:avatar, @uploader1, :mount_on => :another_image)
758
+ @doc = @class.new
759
+ @doc.avatar = stub_file('old.jpeg')
760
+ @doc.save.should be_true
761
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
762
+ end
763
+
764
+ after do
765
+ FileUtils.rm_rf(file_path("uploads"))
766
+ end
767
+
768
+ it "should remove old file if old file had a different path" do
769
+ @doc.avatar = stub_file('new.jpeg')
770
+ @doc.save.should be_true
771
+ File.exists?(public_path('uploads/new.jpeg')).should be_true
772
+ File.exists?(public_path('uploads/old.jpeg')).should be_false
773
+ end
774
+
775
+ it "should not remove file if old file had the same path" do
776
+ @doc.avatar = stub_file('old.jpeg')
777
+ @doc.save.should be_true
778
+ File.exists?(public_path('uploads/old.jpeg')).should be_true
779
+ end
780
+ end
781
+
782
+ # Mongoid::Paranoia support is only part of Mongoid 3.x. It was removed from
783
+ # Mongoid 4.x.
784
+ if defined?(Mongoid::Paranoia)
785
+ describe "with paranoia enabled" do
786
+ before do
787
+ @class = reset_mongo_class
788
+ @class.collection.drop
789
+ @class.class_eval do
790
+ include Mongoid::Paranoia
791
+ end
792
+
793
+ @doc = @class.new(image: stub_file("old.jpeg"))
794
+ @doc.save.should be_true
795
+ end
796
+
797
+ it "should not remove underlying image after #destroy" do
798
+ @doc.destroy.should be_true
799
+ @class.count.should eql(0)
800
+ @class.deleted.count.should eql(1)
801
+ File.exist?(public_path('uploads/old.jpeg')).should be_true
802
+ end
803
+
804
+ it "should remove underlying image after #destroy!" do
805
+ @doc.destroy!.should be_true
806
+ @class.count.should eql(0)
807
+ @class.deleted.count.should eql(0)
808
+ File.exist?(public_path('uploads/old.jpeg')).should be_false
809
+ end
810
+ end
811
+ end
812
+
813
+ context "JSON serialization with multiple uploaders" do
814
+ before do
815
+ @class = reset_mongo_class
816
+ @class.send(:mount_uploader, :textfile,AnotherMongoUploader)
817
+ @event = @class.new
818
+ @event.image = stub_file('old.jpeg')
819
+ @event.textfile = stub_file('old.txt')
820
+ end
821
+
822
+ it "serializes the correct values" do
823
+ @event.serializable_hash["image"]["url"].should match(/old\.jpeg$/)
824
+ @event.serializable_hash["textfile"]["url"].should match(/old\.txt$/)
825
+ end
826
+
827
+ it "should have JSON for each uploader" do
828
+ parsed = JSON.parse(@event.to_json)
829
+ parsed["image"]["url"].should match(/old\.jpeg$/)
830
+ parsed["textfile"]["url"].should match(/old\.txt$/)
831
+ end
832
+ end
833
+
834
+ end