cropped_paperclip 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/.rvmrc +48 -0
- data/Gemfile +7 -0
- data/README.md +17 -0
- data/Rakefile +31 -0
- data/app/.DS_Store +0 -0
- data/app/assets/.DS_Store +0 -0
- data/app/assets/javascripts/.DS_Store +0 -0
- data/app/assets/javascripts/cropped_paperclip/filedrop.js.coffee +254 -0
- data/app/assets/javascripts/cropped_paperclip/upload_crop_scale.js.coffee +319 -0
- data/app/assets/javascripts/es5-shim.js +1105 -0
- data/app/assets/javascripts/uploader.js.coffee +3 -0
- data/app/controllers/cropped_paperclip/application_controller.rb +4 -0
- data/app/controllers/cropped_paperclip/uploads_controller.rb +40 -0
- data/app/helpers/cropped_paperclip/application_helper.rb +4 -0
- data/app/models/upload.rb +119 -0
- data/config/routes.rb +3 -0
- data/cropped_paperclip.gemspec +32 -0
- data/db/migrate/20120510103921_uploads.rb +11 -0
- data/init.rb +4 -0
- data/lib/cropped_paperclip.rb +170 -0
- data/lib/cropped_paperclip/engine.rb +7 -0
- data/lib/cropped_paperclip/glue.rb +20 -0
- data/lib/cropped_paperclip/schema.rb +35 -0
- data/lib/cropped_paperclip/version.rb +3 -0
- data/lib/paperclip/geometry_transformation.rb +80 -0
- data/lib/paperclip/validators/attachment_height_validator.rb +89 -0
- data/lib/paperclip/validators/attachment_width_validator.rb +89 -0
- data/lib/paperclip_processors/offset_thumbnail.rb +86 -0
- data/lib/tasks/cropped_paperclip_tasks.rake +4 -0
- data/script/rails +8 -0
- data/spec/.DS_Store +0 -0
- data/spec/acceptance/acceptance_helper.rb +2 -0
- data/spec/controllers/uploads_controller_spec.rb +5 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.gitkeep +0 -0
- data/spec/dummy/app/models/.gitkeep +0 -0
- data/spec/dummy/app/models/thing.rb +15 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +56 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/migrate/20120510104910_things.rb +8 -0
- data/spec/dummy/db/schema.rb +51 -0
- data/spec/dummy/lib/assets/.gitkeep +0 -0
- data/spec/dummy/log/.gitkeep +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/fixtures/images/.DS_Store +0 -0
- data/spec/fixtures/images/icon.png +0 -0
- data/spec/fixtures/images/test.jpg +0 -0
- data/spec/models/thing_spec.rb +6 -0
- data/spec/models/upload_spec.rb +13 -0
- data/spec/spec_helper.rb +18 -0
- metadata +309 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
module CroppedPaperclip
|
2
|
+
class UploadsController < ::ApplicationController
|
3
|
+
respond_to :js
|
4
|
+
before_filter :find_upload, :only => [:show, :edit, :destroy]
|
5
|
+
before_filter :build_upload, :only => [:new, :create]
|
6
|
+
|
7
|
+
def show
|
8
|
+
respond_with(@upload)
|
9
|
+
end
|
10
|
+
|
11
|
+
def new
|
12
|
+
render
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
@upload.update_attributes(params[:upload])
|
17
|
+
render :partial => 'crop'
|
18
|
+
end
|
19
|
+
|
20
|
+
def edit
|
21
|
+
render :partial => 'crop'
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy
|
25
|
+
@upload.destroy
|
26
|
+
respond_with(@upload)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def find_upload
|
32
|
+
@upload = params[:id] == 'latest' || params[:id].blank? ? current_user.last_upload : Upload.find(params[:id])
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_upload
|
36
|
+
@upload = Upload.create
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# This is a standard upload class that should be useable for most purposes.
|
2
|
+
# We assume that even when the final destination is an S3 bucket, the initial upload
|
3
|
+
# will be held locally.
|
4
|
+
#
|
5
|
+
class Upload < ActiveRecord::Base
|
6
|
+
has_attached_file :file,
|
7
|
+
:path => ":rails_root/public/system/:class/:attachment/:id/:style/:filename",
|
8
|
+
:url => "/system/:class/:attachment/:id/:style/:filename",
|
9
|
+
:processors => lambda { |instance| instance.precrop_processors },
|
10
|
+
:styles => lambda { |attachment| attachment.instance.precrop_styles }
|
11
|
+
|
12
|
+
attr_accessible :file
|
13
|
+
|
14
|
+
# To change precrop dimensions or other thumbnail properties, just monkeypatch this method.
|
15
|
+
#
|
16
|
+
def precrop_styles
|
17
|
+
{
|
18
|
+
:icon => { :geometry => "40x40#" },
|
19
|
+
:thumb => { :geometry => "100x100#" },
|
20
|
+
:precrop => { :geometry => "1600x3000" }
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def precrop_processors
|
25
|
+
[:thumbnail]
|
26
|
+
end
|
27
|
+
|
28
|
+
validates :file, :attachment_presence => true
|
29
|
+
|
30
|
+
## Image dimensions
|
31
|
+
#
|
32
|
+
# We need to know dimensions of the precrop image in order to set up the cropping interface, so we
|
33
|
+
# examine the uploaded file before it is flushed.
|
34
|
+
#
|
35
|
+
after_post_process :read_dimensions
|
36
|
+
|
37
|
+
# *original_geometry* returns the discovered dimensions of the uploaded file as a paperclip geometry object.
|
38
|
+
#
|
39
|
+
def original_geometry
|
40
|
+
@original_geometry ||= Paperclip::Geometry.new(original_width, original_height)
|
41
|
+
end
|
42
|
+
|
43
|
+
# *geometry*, given a style name, returns the dimensions of the file if that style were applied. For
|
44
|
+
# speed we calculate this rather than reading the file, which might be in S3 or some other distant place.
|
45
|
+
#
|
46
|
+
# The logic is in [lib/paperclip/geometry_tranformation.rb](/lib/paperclip/geometry_tranformation.html),
|
47
|
+
# which is a ruby library that mimics the action of imagemagick's convert command.
|
48
|
+
#
|
49
|
+
def geometry(style_name='original')
|
50
|
+
# These calculations are all memoised.
|
51
|
+
@geometry ||= {}
|
52
|
+
begin
|
53
|
+
@geometry[style_name] ||= if style_name.to_s == 'original'
|
54
|
+
# If no style name is given, or it is 'original', we return the original discovered dimensions.
|
55
|
+
original_geometry
|
56
|
+
else
|
57
|
+
# Otherwise, we apply a mock transformation to see what dimensions would result.
|
58
|
+
style = self.file.styles[style_name.to_sym]
|
59
|
+
original_geometry.transformed_by(style.geometry)
|
60
|
+
end
|
61
|
+
rescue Paperclip::TransformationError => e
|
62
|
+
# In case of explosion, we always return the original dimensions so that action can continue.
|
63
|
+
original_geometry
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# *width* returns the width of this image in a given style.
|
68
|
+
#
|
69
|
+
def width(style_name='original')
|
70
|
+
geometry(style_name).width.to_i
|
71
|
+
end
|
72
|
+
|
73
|
+
# *height* returns the height of this image in a given style.
|
74
|
+
#
|
75
|
+
def height(style_name='original')
|
76
|
+
geometry(style_name).height.to_i
|
77
|
+
end
|
78
|
+
|
79
|
+
# *square?* returns true if width and height are the same.
|
80
|
+
#
|
81
|
+
def square?(style_name='original')
|
82
|
+
geometry(style_name).square?
|
83
|
+
end
|
84
|
+
|
85
|
+
# *vertical?* returns true if the image, in the given style, is taller than it is wide.
|
86
|
+
#
|
87
|
+
def vertical?(style_name='original')
|
88
|
+
geometry(style_name).vertical?
|
89
|
+
end
|
90
|
+
|
91
|
+
# *horizontal?* returns true if the image, in the given style, is wider than it is tall.
|
92
|
+
#
|
93
|
+
def horizontal?(style_name='original')
|
94
|
+
geometry(style_name).horizontal?
|
95
|
+
end
|
96
|
+
|
97
|
+
# *dimensions_known?* returns true we have managed to discover the dimensions of the original file.
|
98
|
+
#
|
99
|
+
def dimensions_known?
|
100
|
+
original_width? && original_height?
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
# *read_dimensions* is called after post processing to record in the database the original width, height
|
106
|
+
# and extension of the uploaded file. At this point the file queue will not have been flushed but the upload
|
107
|
+
# should be in place. We grab dimensions from the temp file and calculate thumbnail dimensions later, on demand.
|
108
|
+
#
|
109
|
+
def read_dimensions
|
110
|
+
if file = self.file.queued_for_write[:original]
|
111
|
+
geometry = Paperclip::Geometry.from_file(file)
|
112
|
+
self.original_width = geometry.width
|
113
|
+
self.original_height = geometry.height
|
114
|
+
self.original_extension = File.extname(file.path)
|
115
|
+
end
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cropped_paperclip/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "cropped_paperclip"
|
7
|
+
s.version = CroppedPaperclip::VERSION
|
8
|
+
s.authors = ["William Ross"]
|
9
|
+
s.email = ["will@spanner.org"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{A simple but specific way to attach croppable uploads to any model}
|
12
|
+
s.description = %q{Provides a mechanism for uploading, cropping and reusing images in any of your models.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "cropped_paperclip"
|
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 "rails", "~> 3.2.0"
|
22
|
+
s.add_dependency('paperclip', '~> 3.1.0')
|
23
|
+
s.add_dependency('delayed_job_active_record')
|
24
|
+
|
25
|
+
s.add_development_dependency "rake"
|
26
|
+
s.add_development_dependency "rspec-rails"
|
27
|
+
s.add_development_dependency "shoulda-matchers"
|
28
|
+
s.add_development_dependency "capybara"
|
29
|
+
s.add_development_dependency "acts_as_fu"
|
30
|
+
s.add_development_dependency "sqlite3"
|
31
|
+
|
32
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
require "paperclip"
|
2
|
+
require "paperclip/validators/attachment_height_validator"
|
3
|
+
require "paperclip/validators/attachment_width_validator"
|
4
|
+
require "paperclip/geometry_transformation"
|
5
|
+
require "paperclip_processors/offset_thumbnail"
|
6
|
+
require "cropped_paperclip/engine"
|
7
|
+
require 'cropped_paperclip/glue'
|
8
|
+
|
9
|
+
module CroppedPaperclip
|
10
|
+
mattr_accessor :attachment_path
|
11
|
+
mattr_accessor :attachment_url
|
12
|
+
attachment_path = ":rails_root/public/system/:class/:attachment/:id/:style/:filename"
|
13
|
+
attachment_url = "/system/:class/:attachment/:id/:style/:filename"
|
14
|
+
|
15
|
+
# CroppedPaperclip::ClassMethods is included into ActiveRecord::Base in the same way as the Paperclip module.
|
16
|
+
# It adds a `has_upload` class method that defines an attachment and adds several instance methods
|
17
|
+
# that will return the values that determine its cropping. Those values are usually but not
|
18
|
+
# necessarily given by the user.
|
19
|
+
#
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
## Defining upload columns
|
23
|
+
#
|
24
|
+
# *has_upload* brings in the whole machinery of receiving and cropping an uploaded file. eg.
|
25
|
+
#
|
26
|
+
# class User < ActiveRecord::Base
|
27
|
+
# has_upload :avatar, :size => '120x120#'
|
28
|
+
#
|
29
|
+
# The geometry string will always be treated as though it ended in '#'.
|
30
|
+
#
|
31
|
+
# Set the :cropped option to false if you want the file-upload-sharing mechanism but no cropping step.
|
32
|
+
# In that case any geometry string can be used and it will be passed through intact.
|
33
|
+
#
|
34
|
+
# class Group < ActiveRecord::Base
|
35
|
+
# has_upload :icon, :size => '40x40#', :crop => false
|
36
|
+
#
|
37
|
+
def has_upload(attachment_name=:image, options={})
|
38
|
+
unless !table_exists? || column_names.include?("#{attachment_name}_upload_id")
|
39
|
+
raise RuntimeError, "has_upload(#{attachment_name}) called on class #{self.to_s} but we have no #{attachment_name}_upload_id column"
|
40
|
+
end
|
41
|
+
|
42
|
+
options.reverse_merge!(:geometry => "640x960#", :cropped => true, :whiny => true)
|
43
|
+
options[:geometry].sub!(/\D*$/, '') if options[:cropped]
|
44
|
+
# raise here if geometry is not useable
|
45
|
+
|
46
|
+
class_variable_set(:"@@#{attachment_name}_cropped", options[:cropped])
|
47
|
+
|
48
|
+
# The essential step is present in this style definition. It specifies the OffsetThumbnail processor,
|
49
|
+
# which is similar to the usual thumbnailer but has a more flexible scaling and cropping procedure,
|
50
|
+
# and passes through a couple of callback procs that will return the scaling and cropping arguments
|
51
|
+
# it requires.
|
52
|
+
#
|
53
|
+
crop_style = options[:cropped] == false ? geometry : {
|
54
|
+
:geometry => "#{options[:geometry]}#",
|
55
|
+
:processors => [:offset_thumbnail],
|
56
|
+
|
57
|
+
# The processor will first scale the image to the width that is specified by the scale_width property of the instance
|
58
|
+
:scale => lambda { |att|
|
59
|
+
width = att.instance.send :"#{attachment_name}_scale_width"
|
60
|
+
"#{width || 0}x"
|
61
|
+
},
|
62
|
+
|
63
|
+
# ...then perform the crop described by the width, height, offset_top and offset_left properties of the instance.
|
64
|
+
:crop_and_offset => lambda { |att|
|
65
|
+
width, height = options[:geometry].split('x')
|
66
|
+
left = att.instance.send :"#{attachment_name}_offset_left" || 0
|
67
|
+
top = att.instance.send :"#{attachment_name}_offset_top"
|
68
|
+
"%dx%d%+d%+d" % [width, height, -(left || 0), -(top || 0)]
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
options[:styles] ||= { :icon => "48x48#" }
|
73
|
+
options[:styles].merge!({:cropped => crop_style})
|
74
|
+
|
75
|
+
### Upload association
|
76
|
+
#
|
77
|
+
# [uploads](/app/models/upload.html) are the raw image files uploaded by this person.
|
78
|
+
# They are held separately as the basis for repeatable (and shareable) image assignment.
|
79
|
+
#
|
80
|
+
belongs_to :"#{attachment_name}_upload", :class_name => "Upload"
|
81
|
+
before_save :"read_#{attachment_name}_upload"
|
82
|
+
|
83
|
+
### Attachment
|
84
|
+
#
|
85
|
+
# Image attachments work in the usual Paperclip way except that the :cropped style is applied differently to each instance.
|
86
|
+
# The editing interface allows the user to upload a picture (which creates an upload object) and choose how it is scaled
|
87
|
+
# and cropped (which stores values here).
|
88
|
+
#
|
89
|
+
# The cropped image is created by a [custom processor](/lib/paperclip_processors/offset_thumbnail.html) very similar to
|
90
|
+
# Paperclip::Thumbnail, but which looks up the scale and crop parameters to calculate the imagemagick transformation.
|
91
|
+
#
|
92
|
+
has_attached_file attachment_name, options
|
93
|
+
|
94
|
+
## Maintenance
|
95
|
+
#
|
96
|
+
# *read_[name]_upload* is called before_save. If there is a new upload, or any of our scale and crop values are changed, it will assign
|
97
|
+
# the uploaded file. Even if it's the same file as before, the effect is to trigger post-processing again and apply the current crop and scale values.
|
98
|
+
#
|
99
|
+
define_method :"read_#{attachment_name}_upload" do
|
100
|
+
if self.send(:"reprocess_#{attachment_name}?") && upload = self.send(:"#{attachment_name}_upload")
|
101
|
+
self.send :"#{attachment_name}=", upload.file
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# *reprocess_[name]?* returns true if there have been any changes to the upload association that would necessitate a new crop.
|
106
|
+
#
|
107
|
+
cols = [:upload_id]
|
108
|
+
cols += [:upload_id, :scale_width, :offset_top, :offset_left] if options[:cropped]
|
109
|
+
define_method :"reprocess_#{attachment_name}?" do
|
110
|
+
cols.any? {|col| send(:"#{attachment_name}_#{col}_changed?") }
|
111
|
+
end
|
112
|
+
|
113
|
+
# * [name]_cropped? returns true if the named attachment is cropped on assignment. It can be useful in a form partial.
|
114
|
+
#
|
115
|
+
define_method :"#{attachment_name}_cropped?" do
|
116
|
+
STDERR.puts ">> #{attachment_name}_cropped?"
|
117
|
+
!!class_variable_get(:"@@#{attachment_name}_cropped")
|
118
|
+
end
|
119
|
+
|
120
|
+
define_method :"#{attachment_name}_for_cropping" do
|
121
|
+
if upload = send(:"#{attachment_name}_upload")
|
122
|
+
# here we introduce a convention that might not stand up
|
123
|
+
STDERR.puts ">> #{attachment_name}_for_cropping"
|
124
|
+
upload.url(:"#{attachment_name}")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
## Delay post-processing
|
131
|
+
|
132
|
+
def delay_post_processing(attachment_name=:image)
|
133
|
+
send(:"before_#{attachment_name}_post_process", :"defer_#{attachment_name}_post_processing")
|
134
|
+
after_save(:"resume_#{attachment_name}_post_processing")
|
135
|
+
|
136
|
+
# There are too many thumbnail styles in this class. We can't make the user wait while they are processed,
|
137
|
+
# so the whole job of thumbnailing is spun off into a delayed_job. Since the main publication page displays
|
138
|
+
# the :original style, we can show the user her public page while the rest of the thumbnails are still being
|
139
|
+
# processed.
|
140
|
+
#
|
141
|
+
# The usual post_processing routine is abandoned when we return false from this call.
|
142
|
+
#
|
143
|
+
define_method :"defer_#{attachment_name}_post_processing" do
|
144
|
+
if send(:"reprocess_#{attachment_name}?") && !send(:"awaiting_#{attachment_name}_processing?")
|
145
|
+
send(:"awaiting_#{attachment_name}_processing", true)
|
146
|
+
false
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# The delayed job is created just by interposing the `delay` method in a call to `process_image_styles!`. The effect
|
151
|
+
# is to serialize this object and that call to the database and resume it later when the job runner picks it up.
|
152
|
+
# We can't do that until the publication object has an id, so the call is made from an after_save handler.
|
153
|
+
#
|
154
|
+
define_method :"resume_#{attachment_name}_post_processing" do
|
155
|
+
if send(:"reprocess_#{attachment_name}?") && send(:"awaiting_#{attachment_name}_processing?")
|
156
|
+
self.delay.send(:"process_#{attachment_name}_styles!")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# This is the eventual processing step, to which the delayed job object is just a sort of pointer.
|
161
|
+
# It retrieves the original image from S3 and applies the processing styles.
|
162
|
+
#
|
163
|
+
define_method :"process_#{attachment_name}_styles!" do
|
164
|
+
send(attachment_name).reprocess!
|
165
|
+
update_column(:"awaiting_#{attachment_name}_processing", false)
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'cropped_paperclip/schema'
|
2
|
+
|
3
|
+
module CroppedPaperclip
|
4
|
+
module Glue
|
5
|
+
def self.included base #:nodoc:
|
6
|
+
|
7
|
+
# Extend ActiveRecord::Base with CroppedPaperclip::ClassMethods, as defined in cropped_paperclip.rb.
|
8
|
+
#
|
9
|
+
base.extend ClassMethods
|
10
|
+
|
11
|
+
# Load migration helpers into all the right places.
|
12
|
+
#
|
13
|
+
if defined?(ActiveRecord)
|
14
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, CroppedPaperclip::Schema)
|
15
|
+
ActiveRecord::ConnectionAdapters::Table.send(:include, CroppedPaperclip::Schema)
|
16
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, CroppedPaperclip::Schema)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module CroppedPaperclip
|
2
|
+
# Provides helpers that can be used in migrations.
|
3
|
+
# Copied from, and often makes calls on, the equivalent file in Paperclip.
|
4
|
+
#
|
5
|
+
module Schema
|
6
|
+
UPLOAD_COLUMNS = {
|
7
|
+
:file_name => :string,
|
8
|
+
:content_type => :string,
|
9
|
+
:file_size => :integer,
|
10
|
+
:updated_at => :datetime,
|
11
|
+
:upload_id => :integer,
|
12
|
+
:scale_width => :integer,
|
13
|
+
:scale_height => :integer,
|
14
|
+
:offset_left => :integer,
|
15
|
+
:offset_top => :integer
|
16
|
+
}
|
17
|
+
|
18
|
+
def self.included(base)
|
19
|
+
ActiveRecord::ConnectionAdapters::Table.send :include, TableDefinition
|
20
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, TableDefinition
|
21
|
+
end
|
22
|
+
|
23
|
+
module TableDefinition
|
24
|
+
def uploadable_attachment(*attachment_names)
|
25
|
+
attachment_names.each do |attachment_name|
|
26
|
+
UPLOAD_COLUMNS.each_pair do |column_name, column_type|
|
27
|
+
column("#{attachment_name}_#{column_name}", column_type)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|