delayed_paperclip 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/dev/null +0 -0
- data/lib/delayed/paperclip.rb +72 -0
- data/lib/delayed/paperclip_job.rb +12 -0
- data/lib/delayed_paperclip.rb +6 -0
- data/test/database.yml +4 -0
- data/test/delayed_paperclip_test.rb +107 -0
- data/test/fixtures/12k.png +0 -0
- data/test/test_helper.rb +84 -0
- metadata +85 -0
data/.gitignore
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
|
6
|
+
require 'paperclip'
|
7
|
+
|
8
|
+
desc 'Default: run unit tests.'
|
9
|
+
task :default => [:clean, :test]
|
10
|
+
|
11
|
+
desc 'Test the paperclip plugin.'
|
12
|
+
Rake::TestTask.new(:test) do |t|
|
13
|
+
t.libs << 'lib'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = true
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Generate documentation for the paperclip plugin.'
|
19
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
20
|
+
rdoc.rdoc_dir = 'doc'
|
21
|
+
rdoc.title = 'Delayed::Paperclip'
|
22
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
23
|
+
rdoc.rdoc_files.include('README*')
|
24
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Clean up files.'
|
28
|
+
task :clean do |t|
|
29
|
+
FileUtils.rm_rf "doc"
|
30
|
+
FileUtils.rm_rf "tmp"
|
31
|
+
FileUtils.rm_rf "pkg"
|
32
|
+
FileUtils.rm "test/debug.log" rescue nil
|
33
|
+
FileUtils.rm "test/paperclip.db" rescue nil
|
34
|
+
Dir.glob("paperclip-*.gem").each{|f| FileUtils.rm f }
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
require 'jeweler'
|
39
|
+
Jeweler::Tasks.new do |gemspec|
|
40
|
+
gemspec.name = "delayed_paperclip"
|
41
|
+
gemspec.summary = "Process your Paperclip attachments in the background with delayed_job."
|
42
|
+
gemspec.description = "Process your Paperclip attachments in the background with delayed_job."
|
43
|
+
gemspec.email = "jesse@jstorimer.com"
|
44
|
+
gemspec.homepage = "http://github.com/jstorimer/delayed_paperclip"
|
45
|
+
gemspec.authors = ["Jesse Storimer"]
|
46
|
+
gemspec.add_dependency('paperclip', '>= 2.3.0')
|
47
|
+
gemspec.add_dependency('delayed_job', '>= 1.8.0')
|
48
|
+
end
|
49
|
+
Jeweler::GemcutterTasks.new
|
50
|
+
rescue LoadError
|
51
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler -s http://gemcutter.org"
|
52
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/dev/null
ADDED
File without changes
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Delayed
|
2
|
+
module Paperclip
|
3
|
+
def self.included(base) #:nodoc:
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# +process_in_background+ gives the class it is called on an attribute that maps to a file. This
|
9
|
+
# is typically a file stored somewhere on the filesystem and has been uploaded by a user.
|
10
|
+
# The attribute returns a Paperclip::Attachment object which handles the management of
|
11
|
+
# that file. The intent is to make the attachment as much like a normal attribute. The
|
12
|
+
# thumbnails will be created when the new file is assigned, but they will *not* be saved
|
13
|
+
# until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is
|
14
|
+
# called on it, the attachment will *not* be deleted until +save+ is called. See the
|
15
|
+
# Paperclip::Attachment documentation for more specifics. There are a number of options
|
16
|
+
# you can set to change the behavior of a Paperclip attachment:
|
17
|
+
# * +url+: The full URL of where the attachment is publically accessible. This can just
|
18
|
+
# as easily point to a directory served directly through Apache as it can to an action
|
19
|
+
# that can control permissions. You can specify the full domain and path, but usually
|
20
|
+
# just an absolute path is sufficient. The leading slash *must* be included manually for
|
21
|
+
# absolute paths. The default value is
|
22
|
+
# "/system/:attachment/:id/:style/:filename". See
|
23
|
+
# Paperclip::Attachment#interpolate for more information on variable interpolaton.
|
24
|
+
# :url => "/:class/:attachment/:id/:style_:filename"
|
25
|
+
# :url => "http://some.other.host/stuff/:class/:id_:extension"
|
26
|
+
# * +default_url+: The URL that will be returned if there is no attachment assigned.
|
27
|
+
# This field is interpolated just as the url is. The default value is
|
28
|
+
# "/:attachment/:style/missing.png"
|
29
|
+
# has_attached_file :avatar, :default_url => "/images/default_:style_avatar.png"
|
30
|
+
# User.new.avatar_url(:small) # => "/images/default_small_avatar.png"
|
31
|
+
|
32
|
+
def process_in_background(name)
|
33
|
+
include InstanceMethods
|
34
|
+
|
35
|
+
define_method "#{name}_changed?" do
|
36
|
+
attachment_changed?(name)
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method "halt_processing_for_#{name}" do
|
40
|
+
if self.send("#{name}_changed?")
|
41
|
+
self.processing = true if self.respond_to?(:processing)
|
42
|
+
false # halts processing
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
define_method "enqueue_job_for_#{name}" do
|
47
|
+
if self.send("#{name}_changed?")
|
48
|
+
Delayed::Job.enqueue DelayedPaperclipJob.new(read_attribute(:id), self.class.name, name.to_sym)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
self.send("before_#{name}_post_process", :"halt_processing_for_#{name}")
|
53
|
+
after_save :"enqueue_job_for_#{name}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module InstanceMethods
|
58
|
+
PAPERCLIP_ATTRIBUTES = ['_file_size', '_file_name', '_content_type', '_updated_at']
|
59
|
+
|
60
|
+
def attachment_changed?(name)
|
61
|
+
PAPERCLIP_ATTRIBUTES.each do |attribute|
|
62
|
+
full_attribute = "#{name}#{attribute}_changed?".to_sym
|
63
|
+
|
64
|
+
next unless self.respond_to?(full_attribute)
|
65
|
+
return true if self.send("#{name}#{attribute}_changed?")
|
66
|
+
end
|
67
|
+
|
68
|
+
false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class DelayedPaperclipJob < Struct.new(:instance_id, :instance_klass, :attachment_name)
|
2
|
+
def perform
|
3
|
+
instance = instance_klass.constantize.find(instance_id)
|
4
|
+
|
5
|
+
instance.send(attachment_name).reprocess!
|
6
|
+
|
7
|
+
if instance.respond_to?(:processing)
|
8
|
+
instance.processing = false
|
9
|
+
instance.save
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/test/database.yml
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class DelayedPaperclipTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
build_delayed_jobs
|
6
|
+
reset_dummy
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_attachment_changed
|
10
|
+
@dummy.stubs(:image_file_size_changed?).returns(false)
|
11
|
+
@dummy.stubs(:image_file_name_changed?).returns(false)
|
12
|
+
|
13
|
+
assert !@dummy.image_changed?
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_attachment_changed_when_image_changes
|
17
|
+
@dummy.stubs(:image_file_size_changed?).returns(true)
|
18
|
+
|
19
|
+
assert @dummy.image_changed?
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_before_post_process
|
23
|
+
Dummy.expects(:before_image_post_process)
|
24
|
+
@dummy_class.process_in_background :image
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_halt_processing_if_source_changed
|
28
|
+
@dummy.stubs(:image_changed?).returns(true)
|
29
|
+
assert !@dummy.halt_processing_for_image
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_halt_processing_if_source_changed_and_processing_attribute_defined
|
33
|
+
reset_table("dummies") do |d|
|
34
|
+
d.string :image_file_name
|
35
|
+
d.integer :image_file_size
|
36
|
+
d.boolean :processing
|
37
|
+
end
|
38
|
+
@dummy_class = reset_class "Dummy"
|
39
|
+
@dummy_class.has_attached_file :image
|
40
|
+
@dummy_class.process_in_background :image
|
41
|
+
@dummy = Dummy.new(:image => File.read("#{RAILS_ROOT}/test/fixtures/12k.png"))
|
42
|
+
|
43
|
+
@dummy.stubs(:image_changed?).returns(true)
|
44
|
+
assert !@dummy.halt_processing_for_image
|
45
|
+
assert @dummy.processing
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_halt_processing_if_source_has_not_changed
|
49
|
+
@dummy.stubs(:image_changed?).returns(false)
|
50
|
+
assert_not_equal false, @dummy.halt_processing_for_image
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_after_save
|
54
|
+
Dummy.expects(:after_save)
|
55
|
+
@dummy_class.process_in_background :image
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_enqueue_job_if_source_changed
|
59
|
+
@dummy.stubs(:image_changed?).returns(true)
|
60
|
+
|
61
|
+
original_job_count = Delayed::Job.count
|
62
|
+
@dummy.enqueue_job_for_image
|
63
|
+
|
64
|
+
assert_equal original_job_count + 1, Delayed::Job.count
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_perform_job
|
68
|
+
Paperclip::Attachment.any_instance.expects(:reprocess!)
|
69
|
+
|
70
|
+
@dummy.save!
|
71
|
+
DelayedPaperclipJob.new(@dummy.id, @dummy.class.name, :image).perform
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_perform_job_with_processing_attribute
|
75
|
+
reset_table("dummies") do |d|
|
76
|
+
d.string :image_file_name
|
77
|
+
d.integer :image_file_size
|
78
|
+
d.boolean :processing
|
79
|
+
end
|
80
|
+
@dummy_class = reset_class "Dummy"
|
81
|
+
@dummy_class.has_attached_file :image
|
82
|
+
@dummy_class.process_in_background :image
|
83
|
+
|
84
|
+
@dummy = Dummy.new(:image => File.open("#{RAILS_ROOT}/test/fixtures/12k.png"))
|
85
|
+
|
86
|
+
Paperclip::Attachment.any_instance.expects(:reprocess!)
|
87
|
+
|
88
|
+
@dummy.processing = true
|
89
|
+
@dummy.save!
|
90
|
+
DelayedPaperclipJob.new(@dummy.id, @dummy.class.name, :image).perform
|
91
|
+
|
92
|
+
assert !@dummy.reload.processing
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
def reset_dummy
|
97
|
+
reset_table("dummies") do |d|
|
98
|
+
d.string :image_file_name
|
99
|
+
d.integer :image_file_size
|
100
|
+
end
|
101
|
+
@dummy_class = reset_class "Dummy"
|
102
|
+
@dummy_class.has_attached_file :image
|
103
|
+
@dummy_class.process_in_background :image
|
104
|
+
|
105
|
+
@dummy = Dummy.new(:image => File.open("#{RAILS_ROOT}/test/fixtures/12k.png"))
|
106
|
+
end
|
107
|
+
end
|
Binary file
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'mocha'
|
4
|
+
|
5
|
+
require 'active_record'
|
6
|
+
require 'active_support'
|
7
|
+
|
8
|
+
gem 'sqlite3-ruby'
|
9
|
+
gem 'paperclip'
|
10
|
+
require 'paperclip'
|
11
|
+
gem 'delayed_job'
|
12
|
+
require 'delayed_job'
|
13
|
+
|
14
|
+
FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
|
15
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
16
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
17
|
+
ActiveRecord::Base.establish_connection(config['test'])
|
18
|
+
|
19
|
+
ROOT = File.join(File.dirname(__FILE__), '..')
|
20
|
+
RAILS_ROOT = ROOT
|
21
|
+
RAILS_ENV = "test"
|
22
|
+
|
23
|
+
$LOAD_PATH << File.join(ROOT, 'lib')
|
24
|
+
$LOAD_PATH << File.join(ROOT, 'lib', 'delayed', 'paperclip')
|
25
|
+
$LOAD_PATH << File.join(ROOT, 'test')
|
26
|
+
|
27
|
+
module ActiveRecord
|
28
|
+
class Base
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
require File.join(ROOT, 'lib', 'delayed_paperclip.rb')
|
33
|
+
|
34
|
+
def reset_class class_name
|
35
|
+
ActiveRecord::Base.send(:include, Paperclip)
|
36
|
+
Object.send(:remove_const, class_name) rescue nil
|
37
|
+
klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
|
38
|
+
klass.class_eval{ include Paperclip }
|
39
|
+
klass
|
40
|
+
end
|
41
|
+
|
42
|
+
def reset_table table_name, &block
|
43
|
+
block ||= lambda { |table| true }
|
44
|
+
ActiveRecord::Base.connection.create_table :dummies, {:force => true}, &block
|
45
|
+
end
|
46
|
+
|
47
|
+
def modify_table table_name, &block
|
48
|
+
ActiveRecord::Base.connection.change_table :dummies, &block
|
49
|
+
end
|
50
|
+
|
51
|
+
def rebuild_model options = {}
|
52
|
+
ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
|
53
|
+
table.column :other, :string
|
54
|
+
table.column :avatar_file_name, :string
|
55
|
+
table.column :avatar_content_type, :string
|
56
|
+
table.column :avatar_file_size, :integer
|
57
|
+
table.column :avatar_updated_at, :datetime
|
58
|
+
end
|
59
|
+
rebuild_class options
|
60
|
+
end
|
61
|
+
|
62
|
+
def rebuild_class options = {}
|
63
|
+
ActiveRecord::Base.send(:include, Paperclip)
|
64
|
+
Object.send(:remove_const, "Dummy") rescue nil
|
65
|
+
Object.const_set("Dummy", Class.new(ActiveRecord::Base))
|
66
|
+
Dummy.class_eval do
|
67
|
+
include Paperclip
|
68
|
+
has_attached_file :avatar, options
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_delayed_jobs
|
73
|
+
ActiveRecord::Base.connection.create_table :delayed_jobs, :force => true do |table|
|
74
|
+
table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
|
75
|
+
table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
|
76
|
+
table.text :handler # YAML-encoded string of the object that will do work
|
77
|
+
table.string :last_error # reason for last failure (See Note below)
|
78
|
+
table.datetime :run_at # When to run. Could be Time.now for immediately, or sometime in the future.
|
79
|
+
table.datetime :locked_at # Set when a client is working on this object
|
80
|
+
table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
|
81
|
+
table.string :locked_by # Who is working on this object (if locked)
|
82
|
+
table.timestamps
|
83
|
+
end
|
84
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: delayed_paperclip
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jesse Storimer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-26 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: paperclip
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.3.0
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: delayed_job
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
version:
|
35
|
+
description: Process your Paperclip attachments in the background with delayed_job.
|
36
|
+
email: jesse@jstorimer.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- .gitignore
|
45
|
+
- Rakefile
|
46
|
+
- VERSION
|
47
|
+
- dev/null
|
48
|
+
- lib/delayed/paperclip.rb
|
49
|
+
- lib/delayed/paperclip_job.rb
|
50
|
+
- lib/delayed_paperclip.rb
|
51
|
+
- test/database.yml
|
52
|
+
- test/delayed_paperclip_test.rb
|
53
|
+
- test/fixtures/12k.png
|
54
|
+
- test/test_helper.rb
|
55
|
+
has_rdoc: true
|
56
|
+
homepage: http://github.com/jstorimer/delayed_paperclip
|
57
|
+
licenses: []
|
58
|
+
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --charset=UTF-8
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
version:
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
version:
|
76
|
+
requirements: []
|
77
|
+
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.3.5
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Process your Paperclip attachments in the background with delayed_job.
|
83
|
+
test_files:
|
84
|
+
- test/delayed_paperclip_test.rb
|
85
|
+
- test/test_helper.rb
|