carrierwave_backgrounder 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format progress
2
+ --colour
@@ -1,6 +1,18 @@
1
1
  = CarrierWave Backgrounder
2
2
 
3
- I like CarrierWave. That being said, I don't like tying up app instances waiting for images to process and upload to S3. Depending on the size of the file, this could take a while sometimes timing out Heroku. This gem addresses that. After the file has been uploaded and CarrierWave caches the base file, it halts the process and queues a job.
3
+ I like CarrierWave. That being said, I don't like tying up app instances waiting for images to process. This gem addresses that issue.
4
+
5
+ == Background options
6
+
7
+ There are currently two offerings for backgrounding upload tasks which are as follows;
8
+
9
+ Backgrounder::ORM::Base::process_in_background
10
+
11
+ This method stores the original file and does no processing or versioning. Optionally you can add a column to the database which will be set to nil when the background processing is complete.
12
+
13
+ Backgrounder::ORM::Base::store_in_background
14
+
15
+ This method does nothing to the file after it is cached which makes it super fast. It requires a column in the database which stores the cache location set by carrierwave. The drawback to using this method is the need for a central location to store the cached files. This leave heroku out. Heroku may deploy workers on separate servers from where your dyno cached the files. That being said, I only recommend using this method if you have full control over your temp storage directory.
4
16
 
5
17
  == Installation
6
18
 
@@ -12,44 +24,53 @@ In Rails, add the following your Gemfile:
12
24
 
13
25
  == Getting Started
14
26
 
15
- Add a column to the model you wan to background which will store the temp file location:
27
+ === To use process_in_background
28
+
29
+ In your model:
30
+
31
+ mount_uploader :avatar, AvatarUploader
32
+ process_in_background :avatar
33
+
34
+ === To use store_in_background
16
35
 
36
+ In your model:
37
+
38
+ mount_uploader :avatar, AvatarUploader
39
+ process_in_background :avatar
40
+
41
+ Add a column to the model you want to background which will store the temp file location:
42
+
17
43
  add_column :users, :avatar_tmp, :string
18
44
 
19
45
  In your CarrierWave uploader file:
20
-
46
+
21
47
  class AvatarUploader < CarrierWave::Uploader::Base
22
48
  include ::CarrierWave::Backgrounder::DelayStorage
23
-
49
+
24
50
  #ect...
25
51
  end
26
-
27
- In your model:
28
-
29
- mount_uploader :avatar, AvatarUploader
30
- store_in_background :avatar
31
-
32
- Currently ActiveRecord is the default orm and I have not tested this with others but it should work by adding the following to your carrierwave initializer:
33
-
34
- DataMapper::Model.send(:include, ::CarrierWave::Backgrounder::ORM)
35
- # or
36
- Mongoid::Document::ClassMethods.send(:include, ::CarrierWave::Backgrounder::ORM)
37
- # or
38
- Sequel::Model.send(:extend, ::CarrierWave::Backgrounder::ORM)
39
52
 
40
- == Usage
53
+ == Usage Tips
41
54
 
42
55
  If you need to process/store the upload immediately:
43
56
 
44
- @user.process_upload = true
57
+ @user.process_<column>_upload = true
58
+
59
+ == ORM
45
60
 
46
- == Word Of Caution
61
+ Currently ActiveRecord is the default orm and I have not tested this with others but it should work by adding the following to your carrierwave initializer:
47
62
 
48
- Temp files are stored by default in the tmp directory. They are not guaranteed to be available when your workers process them! For instance, on Heroku, they get blown away on every deploy. If image upload is the main function of your app, I would store the tmp files in a non-volatile directory if you have the option.
63
+ DataMapper::Model.send(:include, ::CarrierWave::Backgrounder::ORM::Base)
64
+ # or
65
+ Mongoid::Document::ClassMethods.send(:include, ::CarrierWave::Backgrounder::ORM::Base)
66
+ # or
67
+ Sequel::Model.send(:extend, ::CarrierWave::Backgrounder::ORM::Base)
68
+
69
+ Contributions are gladly accepted from those who use these orms.
49
70
 
50
71
  == TODO
51
72
 
52
- Transfer tests from rails app.
73
+ More specs
53
74
 
54
75
  == License
55
76
 
data/Rakefile CHANGED
@@ -1,2 +1,12 @@
1
+ # encoding: UTF-8
1
2
  require 'bundler'
2
3
  Bundler::GemHelper.install_tasks
4
+
5
+ require 'rspec/core/rake_task'
6
+ desc "Run all examples"
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
9
+ t.pattern = 'spec/**/*_spec.rb'
10
+ end
11
+
12
+ task :default => :spec
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # encoding: utf-8
2
2
  $:.push File.expand_path("../lib", __FILE__)
3
3
  require "backgrounder/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "carrierwave_backgrounder"
7
- s.version = CarrierwaveBackgrounder::VERSION
7
+ s.version = CarrierWave::Backgrounder::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Larry Sprock"]
10
10
  s.email = ["larry@lucidbleu.com"]
@@ -17,4 +17,9 @@ Gem::Specification.new do |s|
17
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "carrierwave", ["~> 0.5"]
22
+
23
+ s.add_development_dependency "rspec", ["2.5.0"]
24
+ s.add_development_dependency "mocha", ["~> 0.9"]
20
25
  end
@@ -7,7 +7,7 @@ module CarrierWave
7
7
  end
8
8
 
9
9
  def proceed_with_versioning?
10
- !model.respond_to?(:process_upload) || model.process_upload
10
+ !model.respond_to?(:"process_#{mounted_as}_upload") || model.send(:"process_#{mounted_as}_upload")
11
11
  end
12
12
  end # DelayStorage
13
13
 
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+ require 'active_record'
3
+
4
+ module CarrierWave
5
+ module Backgrounder
6
+ module ORM
7
+
8
+ module ActiveRecord
9
+ include CarrierWave::Backgrounder::ORM::Base
10
+
11
+ def process_in_background(column, worker=::CarrierWave::Workers::ProcessAsset)
12
+ super
13
+
14
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
15
+ def trigger_#{column}_background_processing?
16
+ process_#{column}_upload != true && #{column}_changed?
17
+ end
18
+ RUBY
19
+ end
20
+
21
+ def store_in_background(column, worker=::CarrierWave::Workers::StoreAsset)
22
+ super
23
+
24
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
25
+ def trigger_#{column}_background_storage?
26
+ process_#{column}_upload != true && #{column}_changed?
27
+ end
28
+ RUBY
29
+ end
30
+ end # ActiveRecord
31
+
32
+ end # ORM
33
+ end # Backgrounder
34
+ end # CarrierWave
35
+
36
+ ActiveRecord::Base.extend CarrierWave::Backgrounder::ORM::ActiveRecord
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+ require 'backgrounder/workers'
3
+
4
+ module CarrierWave
5
+ module Backgrounder
6
+ module ORM
7
+
8
+ ##
9
+ # Base class for all things orm
10
+ module Base
11
+
12
+ ##
13
+ # User#process_in_background will process and create versions in a background process.
14
+ #
15
+ # class User < ActiveRecord::Base
16
+ # mount_uploader :avatar, AvatarUploader
17
+ # process_in_background :avatar
18
+ # end
19
+ #
20
+ # The above adds a User#process_upload method which can be used at times when you want to bypass
21
+ # background storage and processing.
22
+ #
23
+ # @user.process_avatar = true
24
+ # @user.save
25
+ #
26
+ # You can also pass in your own workers using the second argument in case you need other things done
27
+ # during processing.
28
+ #
29
+ # class User < ActiveRecord::Base
30
+ # mount_uploader :avatar, AvatarUploader
31
+ # process_in_background :avatar, CustomWorker
32
+ # end
33
+ #
34
+ # In addition you can also add a column to the database appended by _processing with a type of boolean
35
+ # which can be used to check if processing is complete.
36
+ #
37
+ # def self.up
38
+ # add_column :users, :avatar_processing, :boolean
39
+ # end
40
+ #
41
+ def process_in_background(column, worker=::CarrierWave::Workers::ProcessAsset)
42
+ send :before_save, :"set_#{column}_processing", :if => :"trigger_#{column}_background_processing?"
43
+ send :after_save, :"enqueue_#{column}_background_job", :if => :"trigger_#{column}_background_processing?"
44
+
45
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
46
+ attr_accessor :process_#{column}_upload
47
+
48
+ def set_#{column}_processing
49
+ self.#{column}_processing = true if respond_to?(:#{column}_processing)
50
+ end
51
+
52
+ def enqueue_#{column}_background_job
53
+ ::Delayed::Job.enqueue #{worker}.new(self.class, id, #{column}.mounted_as)
54
+ end
55
+
56
+ def trigger_#{column}_background_processing?
57
+ process_#{column}_upload != true
58
+ end
59
+
60
+ RUBY
61
+ end
62
+
63
+ ##
64
+ # #store_in_background will process, version and store uploads in a background process.
65
+ #
66
+ # class User < ActiveRecord::Base
67
+ # mount_uploader :avatar, AvatarUploader
68
+ # store_in_background :avatar
69
+ # end
70
+ #
71
+ # The above adds a User#process_<column> method which can be used at times when you want to bypass
72
+ # background storage and processing.
73
+ #
74
+ # @user.process_avatar = true
75
+ # @user.save
76
+ #
77
+ # You can also pass in your own workers using the second argument in case you need other things done
78
+ # durring processing.
79
+ #
80
+ # class User < ActiveRecord::Base
81
+ # mount_uploader :avatar, AvatarUploader
82
+ # store_in_background :avatar, CustomWorker
83
+ # end
84
+ #
85
+ def store_in_background(column, worker=::CarrierWave::Workers::StoreAsset)
86
+ send :after_save, :"enqueue_#{column}_background_job", :if => :"trigger_#{column}_background_storage?"
87
+
88
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
89
+ attr_accessor :process_#{column}_upload
90
+
91
+ def write_#{column}_identifier
92
+ super() and return if process_upload
93
+ self.#{column}_tmp = _mounter(:#{column}).cache_name
94
+ end
95
+
96
+ def store_#{column}!
97
+ super() if process_#{column}_upload
98
+ end
99
+
100
+ def enqueue_#{column}_background_job
101
+ ::Delayed::Job.enqueue #{worker}.new(self.class, id, #{column}.mounted_as)
102
+ end
103
+
104
+ def trigger_#{column}_background_storage?
105
+ process_#{column}_upload != true
106
+ end
107
+
108
+ RUBY
109
+ end
110
+
111
+ end # Base
112
+
113
+ end #ORM
114
+ end #Backgrounder
115
+ end #CarrierWave
@@ -1,3 +1,5 @@
1
- module CarrierwaveBackgrounder
2
- VERSION = "0.0.2"
1
+ module CarrierWave
2
+ module Backgrounder
3
+ VERSION = "0.0.3"
4
+ end
3
5
  end
@@ -0,0 +1,2 @@
1
+ require 'backgrounder/workers/process_asset'
2
+ require 'backgrounder/workers/store_asset'
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ class ProcessAsset < Struct.new(:klass, :id, :column)
6
+
7
+ def perform
8
+ record = klass.find id
9
+ record.send(:"process_#{column}_upload=", true)
10
+ if record.send(:"#{column}").recreate_versions! && record.respond_to?(:"#{column}_processing")
11
+ record.update_attribute :"#{column}_processing", nil
12
+ end
13
+ end
14
+
15
+ end # ProcessAsset
16
+
17
+ end # Workers
18
+ end # Backgrounder
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  module CarrierWave
2
3
  module Workers
3
4
 
@@ -5,11 +6,12 @@ module CarrierWave
5
6
 
6
7
  def perform
7
8
  record = klass.find id
8
- if record.send :"#{column}_tmp"
9
- cache_dir = [record.send(:"#{column}").root, record.send(:"#{column}").cache_dir].join("/")
10
- cache_path = [cache_dir, record.send(:"#{column}_tmp")].join("/")
9
+ if tmp = record.send(:"#{column}_tmp")
10
+ asset = record.send(:"#{column}")
11
+ cache_dir = [asset.root, asset.cache_dir].join("/")
12
+ cache_path = [cache_dir, tmp].join("/")
11
13
 
12
- record.send :"process_upload=", true
14
+ record.send :"process_#{column}_upload=", true
13
15
  record.send :"#{column}=", File.open(cache_path)
14
16
  record.send :"#{column}_tmp=", nil
15
17
  if record.save!
@@ -21,4 +23,4 @@ module CarrierWave
21
23
  end # StoreAsset
22
24
 
23
25
  end # Workers
24
- end # Backgrounder
26
+ end # Backgrounder
@@ -1,7 +1,10 @@
1
1
  module CarrierWave
2
2
  module Backgrounder
3
3
  autoload :DelayStorage, 'backgrounder/delay_storage'
4
- autoload :ORM, 'backgrounder/orm'
4
+
5
+ module ORM
6
+ autoload :Base, 'backgrounder/orm/base'
7
+ end
5
8
  end
6
9
  end
7
10
 
@@ -11,10 +14,10 @@ if defined?(Rails)
11
14
  class Railtie < Rails::Railtie
12
15
  initializer "carrierwave_backgrounder.active_record" do
13
16
  ActiveSupport.on_load :active_record do
14
- ::ActiveRecord::Base.send :include, ::CarrierWave::Backgrounder::ORM
17
+ require 'backgrounder/orm/activerecord'
15
18
  end
16
19
  end
17
20
  end
18
21
  end
19
22
  end
20
- end
23
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+
5
+ RSpec.configure do |c|
6
+ c.mock_with :mocha
7
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'backgrounder/workers/process_asset'
4
+
5
+ describe worker = CarrierWave::Workers::ProcessAsset do
6
+ before do
7
+ @user = mock('User')
8
+ @image = mock('UserAsset')
9
+ @worker = worker.new(@user, '22', :image)
10
+ end
11
+
12
+ context "#perform" do
13
+ it 'processes versions' do
14
+ @user.expects(:find).with('22').returns(@user).once
15
+ @user.expects(:image).once.returns(@image)
16
+ @user.expects(:process_image_upload=).with(true).once
17
+
18
+ @image.expects(:recreate_versions!).once.returns(true)
19
+ @user.expects(:respond_to?).with(:image_processing).once.returns(true)
20
+ @user.expects(:update_attribute).with(:image_processing, nil).once
21
+
22
+ @worker.perform
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'backgrounder/workers/store_asset'
4
+
5
+ describe worker = CarrierWave::Workers::StoreAsset do
6
+ before do
7
+ @user = mock('User')
8
+ @image = mock('UserAsset')
9
+ @worker = worker.new(@user, '22', :image)
10
+ end
11
+
12
+ context "#perform" do
13
+ it 'processes versions' do
14
+ File.expects(:open).with('../fixtures/test.jpg').once.returns('apple')
15
+ FileUtils.expects(:rm).with('../fixtures/test.jpg').once
16
+ @user.expects(:find).with('22').once.returns(@user)
17
+ @user.expects(:image_tmp).once.returns('test.jpg')
18
+ @user.expects(:image).once.returns(@image)
19
+ @image.expects(:root).once.returns('..')
20
+ @image.expects(:cache_dir).once.returns('fixtures')
21
+ @user.expects(:process_image_upload=).with(true).once
22
+ @user.expects(:image=).with('apple').once
23
+ @user.expects(:image_tmp=).with(nil).once
24
+ @user.expects(:save!).once.returns(true)
25
+
26
+ @worker.perform
27
+ end
28
+ end
29
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: carrierwave_backgrounder
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.2
5
+ version: 0.0.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Larry Sprock
@@ -10,10 +10,42 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-28 00:00:00 -07:00
13
+ date: 2011-04-29 00:00:00 -07:00
14
14
  default_executable:
15
- dependencies: []
16
-
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: carrierwave
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: "0.5"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - "="
34
+ - !ruby/object:Gem::Version
35
+ version: 2.5.0
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: mocha
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: "0.9"
47
+ type: :development
48
+ version_requirements: *id003
17
49
  description:
18
50
  email:
19
51
  - larry@lucidbleu.com
@@ -25,16 +57,22 @@ extra_rdoc_files: []
25
57
 
26
58
  files:
27
59
  - .gitignore
60
+ - .rspec
28
61
  - Gemfile
29
62
  - README.rdoc
30
63
  - Rakefile
31
64
  - carrierwave_backgrounder.gemspec
32
65
  - lib/backgrounder/delay_storage.rb
33
- - lib/backgrounder/orm.rb
66
+ - lib/backgrounder/orm/activerecord.rb
67
+ - lib/backgrounder/orm/base.rb
34
68
  - lib/backgrounder/version.rb
69
+ - lib/backgrounder/workers.rb
70
+ - lib/backgrounder/workers/process_asset.rb
35
71
  - lib/backgrounder/workers/store_asset.rb
36
72
  - lib/carrierwave_backgrounder.rb
37
73
  - spec/spec_helper.rb
74
+ - spec/workers/process_asset_spec.rb
75
+ - spec/workers/store_asset_spec.rb
38
76
  has_rdoc: true
39
77
  homepage: ""
40
78
  licenses: []
@@ -65,3 +103,5 @@ specification_version: 3
65
103
  summary: Offload CarrierWave's image processing and storage to a background process using Delayed Job
66
104
  test_files:
67
105
  - spec/spec_helper.rb
106
+ - spec/workers/process_asset_spec.rb
107
+ - spec/workers/store_asset_spec.rb
@@ -1,38 +0,0 @@
1
- require 'backgrounder/workers/store_asset'
2
-
3
- module CarrierWave
4
- module Backgrounder
5
-
6
- module ORM
7
- extend ActiveSupport::Concern
8
-
9
- module ClassMethods
10
-
11
- def store_in_background(column, version=false)
12
- send :after_save, :"enqueue_#{column}_storage"
13
-
14
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
15
- attr_accessor :process_upload
16
-
17
- def write_#{column}_identifier
18
- super() and return if process_upload
19
- self.#{column}_tmp = _mounter(:#{column}).cache_name
20
- end
21
-
22
- def store_#{column}!
23
- super() if process_upload
24
- end
25
-
26
- def enqueue_#{column}_storage
27
- if !process_upload && #{column}_tmp
28
- ::Delayed::Job.enqueue ::CarrierWave::Workers::StoreAsset.new(self.class, id, #{column}.mounted_as)
29
- end
30
- end
31
- RUBY
32
- end
33
-
34
- end # ClassMethods
35
- end # ActiveRecord
36
-
37
- end #Backgrounder
38
- end #CarrierWave