tristandunn-paperclip 2.3.1 → 2.3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +7 -3
- data/lib/paperclip.rb +20 -13
- data/lib/paperclip/attachment.rb +47 -127
- data/lib/paperclip/interpolations.rb +19 -16
- data/lib/paperclip/iostream.rb +2 -1
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +2 -3
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +6 -6
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +5 -3
- data/lib/paperclip/storage.rb +31 -14
- data/lib/paperclip/style.rb +90 -0
- data/lib/paperclip/thumbnail.rb +4 -2
- data/lib/paperclip/upfile.rb +3 -2
- data/shoulda_macros/paperclip.rb +49 -0
- data/test/attachment_test.rb +28 -43
- data/test/fixtures/s3.yml +4 -0
- data/test/helper.rb +10 -1
- data/test/interpolations_test.rb +5 -1
- data/test/iostream_test.rb +9 -2
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +1 -0
- data/test/matchers/validate_attachment_presence_matcher_test.rb +3 -1
- data/test/matchers/validate_attachment_size_matcher_test.rb +1 -0
- data/test/paperclip_test.rb +26 -40
- data/test/storage_test.rb +64 -7
- data/test/style_test.rb +141 -0
- data/test/thumbnail_test.rb +1 -1
- data/test/upfile_test.rb +28 -0
- metadata +49 -11
data/Rakefile
CHANGED
@@ -60,7 +60,7 @@ exclude_file_globs = ["test/s3.yml",
|
|
60
60
|
"test/tmp",
|
61
61
|
"test/tmp/*"]
|
62
62
|
spec = Gem::Specification.new do |s|
|
63
|
-
s.name = "paperclip"
|
63
|
+
s.name = "tristandunn-paperclip"
|
64
64
|
s.version = Paperclip::VERSION
|
65
65
|
s.author = "Jon Yurek"
|
66
66
|
s.email = "jyurek@thoughtbot.com"
|
@@ -75,8 +75,12 @@ spec = Gem::Specification.new do |s|
|
|
75
75
|
s.extra_rdoc_files = FileList["README*"].to_a
|
76
76
|
s.rdoc_options << '--line-numbers' << '--inline-source'
|
77
77
|
s.requirements << "ImageMagick"
|
78
|
-
s.add_development_dependency '
|
79
|
-
s.add_development_dependency 'mocha'
|
78
|
+
s.add_development_dependency 'shoulda'
|
79
|
+
s.add_development_dependency 'jferris-mocha', '>= 0.9.5.0.1241126838'
|
80
|
+
s.add_development_dependency 'aws-s3'
|
81
|
+
s.add_development_dependency 'sqlite3-ruby'
|
82
|
+
s.add_development_dependency 'activerecord'
|
83
|
+
s.add_development_dependency 'activesupport'
|
80
84
|
end
|
81
85
|
|
82
86
|
desc "Print a list of the files to be put into the gem"
|
data/lib/paperclip.rb
CHANGED
@@ -25,6 +25,7 @@
|
|
25
25
|
#
|
26
26
|
# See the +has_attached_file+ documentation for more details.
|
27
27
|
|
28
|
+
require 'erb'
|
28
29
|
require 'tempfile'
|
29
30
|
require 'paperclip/upfile'
|
30
31
|
require 'paperclip/iostream'
|
@@ -33,6 +34,7 @@ require 'paperclip/processor'
|
|
33
34
|
require 'paperclip/thumbnail'
|
34
35
|
require 'paperclip/storage'
|
35
36
|
require 'paperclip/interpolations'
|
37
|
+
require 'paperclip/style'
|
36
38
|
require 'paperclip/attachment'
|
37
39
|
if defined? RAILS_ROOT
|
38
40
|
Dir.glob(File.join(File.expand_path(RAILS_ROOT), "lib", "paperclip_processors", "*.rb")).each do |processor|
|
@@ -44,7 +46,7 @@ end
|
|
44
46
|
# documentation for Paperclip::ClassMethods for more useful information.
|
45
47
|
module Paperclip
|
46
48
|
|
47
|
-
VERSION = "2.3.1"
|
49
|
+
VERSION = "2.3.1.1"
|
48
50
|
|
49
51
|
class << self
|
50
52
|
# Provides configurability to Paperclip. There are a number of options available, such as:
|
@@ -238,7 +240,7 @@ module Paperclip
|
|
238
240
|
|
239
241
|
validates_each(name) do |record, attr, value|
|
240
242
|
attachment = record.attachment_for(name)
|
241
|
-
attachment.send(:flush_errors)
|
243
|
+
attachment.send(:flush_errors)
|
242
244
|
end
|
243
245
|
end
|
244
246
|
|
@@ -256,11 +258,13 @@ module Paperclip
|
|
256
258
|
max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
|
257
259
|
range = (min..max)
|
258
260
|
message = options[:message] || "file size must be between :min and :max bytes."
|
261
|
+
message = message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s)
|
259
262
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
263
|
+
validates_inclusion_of :"#{name}_file_size",
|
264
|
+
:in => range,
|
265
|
+
:message => message,
|
266
|
+
:if => options[:if],
|
267
|
+
:unless => options[:unless]
|
264
268
|
end
|
265
269
|
|
266
270
|
# Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true.
|
@@ -278,9 +282,10 @@ module Paperclip
|
|
278
282
|
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
279
283
|
def validates_attachment_presence name, options = {}
|
280
284
|
message = options[:message] || "must be set."
|
281
|
-
|
282
|
-
|
283
|
-
|
285
|
+
validates_presence_of :"#{name}_file_name",
|
286
|
+
:message => message,
|
287
|
+
:if => options[:if],
|
288
|
+
:unless => options[:unless]
|
284
289
|
end
|
285
290
|
|
286
291
|
# Places ActiveRecord-style validations on the content type of the file
|
@@ -300,10 +305,12 @@ module Paperclip
|
|
300
305
|
# model, content_type validation will work _ONLY upon assignment_ and
|
301
306
|
# re-validation after the instance has been reloaded will always succeed.
|
302
307
|
def validates_attachment_content_type name, options = {}
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
308
|
+
types = [options.delete(:content_type)].flatten
|
309
|
+
validates_each(:"#{name}_content_type", options) do |record, attr, value|
|
310
|
+
unless types.any?{|t| t === value }
|
311
|
+
record.errors.add(:"#{name}_content_type", :inclusion, :default => options[:message], :value => value)
|
312
|
+
end
|
313
|
+
end
|
307
314
|
end
|
308
315
|
|
309
316
|
# Returns the attachment definitions defined by each call to
|
data/lib/paperclip/attachment.rb
CHANGED
@@ -7,18 +7,19 @@ module Paperclip
|
|
7
7
|
|
8
8
|
def self.default_options
|
9
9
|
@default_options ||= {
|
10
|
-
:url
|
11
|
-
:path
|
12
|
-
:styles
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
10
|
+
:url => "/system/:attachment/:id/:style/:filename",
|
11
|
+
:path => ":rails_root/public:url",
|
12
|
+
:styles => {},
|
13
|
+
:processors => [:thumbnail],
|
14
|
+
:convert_options => {},
|
15
|
+
:default_url => "/:attachment/:style/missing.png",
|
16
|
+
:default_style => :original,
|
17
|
+
:storage => :filesystem,
|
18
|
+
:whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails]
|
18
19
|
}
|
19
20
|
end
|
20
21
|
|
21
|
-
attr_reader :name, :instance, :
|
22
|
+
attr_reader :name, :instance, :default_style, :convert_options, :queued_for_write, :whiny, :options
|
22
23
|
|
23
24
|
# Creates an Attachment object. +name+ is the name of the attachment,
|
24
25
|
# +instance+ is the ActiveRecord object instance it's attached to, and
|
@@ -34,33 +35,42 @@ module Paperclip
|
|
34
35
|
@path = options[:path]
|
35
36
|
@path = @path.call(self) if @path.is_a?(Proc)
|
36
37
|
@styles = options[:styles]
|
37
|
-
@
|
38
|
+
@normalized_styles = nil
|
38
39
|
@default_url = options[:default_url]
|
39
|
-
@validations = options[:validations]
|
40
40
|
@default_style = options[:default_style]
|
41
41
|
@storage = options[:storage]
|
42
42
|
@whiny = options[:whiny_thumbnails] || options[:whiny]
|
43
|
-
@convert_options = options[:convert_options]
|
44
|
-
@processors = options[:processors]
|
43
|
+
@convert_options = options[:convert_options]
|
44
|
+
@processors = options[:processors]
|
45
45
|
@options = options
|
46
46
|
@queued_for_delete = []
|
47
47
|
@queued_for_write = {}
|
48
48
|
@errors = {}
|
49
|
-
@validation_errors = nil
|
50
49
|
@dirty = false
|
51
50
|
|
52
|
-
normalize_style_definition
|
53
51
|
initialize_storage
|
54
52
|
end
|
53
|
+
|
54
|
+
def styles
|
55
|
+
unless @normalized_styles
|
56
|
+
@normalized_styles = {}
|
57
|
+
(@styles.respond_to?(:call) ? @styles.call(self) : @styles).each do |name, args|
|
58
|
+
@normalized_styles[name] = Paperclip::Style.new(name, args, self)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
@normalized_styles
|
62
|
+
end
|
63
|
+
|
64
|
+
def processors
|
65
|
+
@processors.respond_to?(:call) ? @processors.call(instance) : @processors
|
66
|
+
end
|
55
67
|
|
56
68
|
# What gets called when you call instance.attachment = File. It clears
|
57
|
-
# errors, assigns attributes, processes the file
|
69
|
+
# errors, assigns attributes, and processes the file. It
|
58
70
|
# also queues up the previous file for deletion, to be flushed away on
|
59
71
|
# #save of its host. In addition to form uploads, you can also assign
|
60
72
|
# another Paperclip attachment:
|
61
73
|
# new_user.avatar = old_user.avatar
|
62
|
-
# If the file that is assigned is not valid, the processing (i.e.
|
63
|
-
# thumbnailing, etc) will NOT be run.
|
64
74
|
def assign uploaded_file
|
65
75
|
ensure_required_accessors!
|
66
76
|
|
@@ -84,13 +94,12 @@ module Paperclip
|
|
84
94
|
|
85
95
|
@dirty = true
|
86
96
|
|
87
|
-
post_process
|
97
|
+
post_process
|
88
98
|
|
89
99
|
# Reset the file size if the original file was reprocessed.
|
90
100
|
instance_write(:file_size, @queued_for_write[:original].size.to_i)
|
91
101
|
ensure
|
92
102
|
uploaded_file.close if close_uploaded_file
|
93
|
-
validate
|
94
103
|
end
|
95
104
|
|
96
105
|
# Returns the public URL of the attachment, with a given style. Note that
|
@@ -100,8 +109,8 @@ module Paperclip
|
|
100
109
|
# security, however, for performance reasons. set
|
101
110
|
# include_updated_timestamp to false if you want to stop the attachment
|
102
111
|
# update time appended to the url
|
103
|
-
def url
|
104
|
-
url = original_filename.nil? ? interpolate(@default_url,
|
112
|
+
def url style_name = default_style, include_updated_timestamp = true
|
113
|
+
url = original_filename.nil? ? interpolate(@default_url, style_name) : interpolate(@url, style_name)
|
105
114
|
include_updated_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url
|
106
115
|
end
|
107
116
|
|
@@ -109,19 +118,13 @@ module Paperclip
|
|
109
118
|
# file is stored in the filesystem the path refers to the path of the file
|
110
119
|
# on disk. If the file is stored in S3, the path is the "key" part of the
|
111
120
|
# URL, and the :bucket option refers to the S3 bucket.
|
112
|
-
def path
|
113
|
-
original_filename.nil? ? nil : interpolate(@path,
|
121
|
+
def path style_name = default_style
|
122
|
+
original_filename.nil? ? nil : interpolate(@path, style_name)
|
114
123
|
end
|
115
124
|
|
116
125
|
# Alias to +url+
|
117
|
-
def to_s
|
118
|
-
url(
|
119
|
-
end
|
120
|
-
|
121
|
-
# Returns true if there are no errors on this attachment.
|
122
|
-
def valid?
|
123
|
-
validate
|
124
|
-
errors.empty?
|
126
|
+
def to_s style_name = nil
|
127
|
+
url(style_name)
|
125
128
|
end
|
126
129
|
|
127
130
|
# Returns an array containing the errors on this attachment.
|
@@ -137,15 +140,10 @@ module Paperclip
|
|
137
140
|
# Saves the file, if there are no errors. If there are, it flushes them to
|
138
141
|
# the instance's errors and returns false, cancelling the save.
|
139
142
|
def save
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
true
|
145
|
-
else
|
146
|
-
flush_errors
|
147
|
-
false
|
148
|
-
end
|
143
|
+
flush_deletes
|
144
|
+
flush_writes
|
145
|
+
@dirty = false
|
146
|
+
true
|
149
147
|
end
|
150
148
|
|
151
149
|
# Clears out the attachment. Has the same effect as previously assigning
|
@@ -154,7 +152,6 @@ module Paperclip
|
|
154
152
|
def clear
|
155
153
|
queue_existing_for_delete
|
156
154
|
@errors = {}
|
157
|
-
@validation_errors = nil
|
158
155
|
end
|
159
156
|
|
160
157
|
# Destroys the attachment. Has the same effect as previously assigning
|
@@ -187,7 +184,7 @@ module Paperclip
|
|
187
184
|
# lives in the <attachment>_updated_at attribute of the model.
|
188
185
|
def updated_at
|
189
186
|
time = instance_read(:updated_at)
|
190
|
-
time && time.to_i
|
187
|
+
time && time.to_f.to_i
|
191
188
|
end
|
192
189
|
|
193
190
|
# Paths and URLs can have a number of variables interpolated into them
|
@@ -267,82 +264,6 @@ module Paperclip
|
|
267
264
|
file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type))
|
268
265
|
end
|
269
266
|
|
270
|
-
def validate #:nodoc:
|
271
|
-
unless @validation_errors
|
272
|
-
@validation_errors = @validations.inject({}) do |errors, validation|
|
273
|
-
name, options = validation
|
274
|
-
errors[name] = send(:"validate_#{name}", options) if allow_validation?(options)
|
275
|
-
errors
|
276
|
-
end
|
277
|
-
@validation_errors.reject!{|k,v| v == nil }
|
278
|
-
@errors.merge!(@validation_errors)
|
279
|
-
end
|
280
|
-
@validation_errors
|
281
|
-
end
|
282
|
-
|
283
|
-
def allow_validation? options #:nodoc:
|
284
|
-
(options[:if].nil? || check_guard(options[:if])) && (options[:unless].nil? || !check_guard(options[:unless]))
|
285
|
-
end
|
286
|
-
|
287
|
-
def check_guard guard #:nodoc:
|
288
|
-
if guard.respond_to? :call
|
289
|
-
guard.call(instance)
|
290
|
-
elsif ! guard.blank?
|
291
|
-
instance.send(guard.to_s)
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
def validate_size options #:nodoc:
|
296
|
-
if file? && !options[:range].include?(size.to_i)
|
297
|
-
options[:message].gsub(/:min/, options[:min].to_s).gsub(/:max/, options[:max].to_s)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
def validate_presence options #:nodoc:
|
302
|
-
options[:message] unless file?
|
303
|
-
end
|
304
|
-
|
305
|
-
def validate_content_type options #:nodoc:
|
306
|
-
valid_types = [options[:content_type]].flatten
|
307
|
-
unless original_filename.blank?
|
308
|
-
unless valid_types.blank?
|
309
|
-
content_type = instance_read(:content_type)
|
310
|
-
unless valid_types.any?{|t| content_type.nil? || t === content_type }
|
311
|
-
options[:message] || "is not one of the allowed file types."
|
312
|
-
end
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
def normalize_style_definition #:nodoc:
|
318
|
-
@styles.each do |name, args|
|
319
|
-
unless args.is_a? Hash
|
320
|
-
dimensions, format = [args, nil].flatten[0..1]
|
321
|
-
format = nil if format.blank?
|
322
|
-
@styles[name] = {
|
323
|
-
:processors => @processors,
|
324
|
-
:geometry => dimensions,
|
325
|
-
:format => format,
|
326
|
-
:whiny => @whiny,
|
327
|
-
:convert_options => extra_options_for(name)
|
328
|
-
}
|
329
|
-
else
|
330
|
-
@styles[name] = {
|
331
|
-
:processors => @processors,
|
332
|
-
:whiny => @whiny,
|
333
|
-
:convert_options => extra_options_for(name)
|
334
|
-
}.merge(@styles[name])
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
def solidify_style_definitions #:nodoc:
|
340
|
-
@styles.each do |name, args|
|
341
|
-
@styles[name][:geometry] = @styles[name][:geometry].call(instance) if @styles[name][:geometry].respond_to?(:call)
|
342
|
-
@styles[name][:processors] = @styles[name][:processors].call(instance) if @styles[name][:processors].respond_to?(:call)
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
267
|
def initialize_storage #:nodoc:
|
347
268
|
@storage_module = Paperclip::Storage.const_get(@storage.to_s.capitalize)
|
348
269
|
self.extend(@storage_module)
|
@@ -359,7 +280,6 @@ module Paperclip
|
|
359
280
|
|
360
281
|
def post_process #:nodoc:
|
361
282
|
return if @queued_for_write[:original].nil?
|
362
|
-
solidify_style_definitions
|
363
283
|
return if fire_events(:before)
|
364
284
|
post_process_styles
|
365
285
|
return if fire_events(:after)
|
@@ -375,11 +295,11 @@ module Paperclip
|
|
375
295
|
end
|
376
296
|
|
377
297
|
def post_process_styles #:nodoc:
|
378
|
-
|
298
|
+
styles.each do |name, style|
|
379
299
|
begin
|
380
|
-
raise RuntimeError.new("Style #{name} has no processors defined.") if
|
381
|
-
@queued_for_write[name] =
|
382
|
-
Paperclip.processor(processor).make(file,
|
300
|
+
raise RuntimeError.new("Style #{name} has no processors defined.") if style.processors.blank?
|
301
|
+
@queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
|
302
|
+
Paperclip.processor(processor).make(file, style.processor_options, self)
|
383
303
|
end
|
384
304
|
rescue PaperclipError => e
|
385
305
|
log("An error was received while processing: #{e.inspect}")
|
@@ -388,13 +308,13 @@ module Paperclip
|
|
388
308
|
end
|
389
309
|
end
|
390
310
|
|
391
|
-
def interpolate pattern,
|
392
|
-
Paperclip::Interpolations.interpolate(pattern, self,
|
311
|
+
def interpolate pattern, style_name = default_style #:nodoc:
|
312
|
+
Paperclip::Interpolations.interpolate(pattern, self, style_name)
|
393
313
|
end
|
394
314
|
|
395
315
|
def queue_existing_for_delete #:nodoc:
|
396
316
|
return unless file?
|
397
|
-
@queued_for_delete += [:original,
|
317
|
+
@queued_for_delete += [:original, *styles.keys].uniq.map do |style|
|
398
318
|
path(style) if exists?(style)
|
399
319
|
end.compact
|
400
320
|
instance_write(:file_name, nil)
|
@@ -34,72 +34,75 @@ module Paperclip
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# Returns the filename, the same way as ":basename.:extension" would.
|
37
|
-
def filename attachment,
|
38
|
-
"#{basename(attachment,
|
37
|
+
def filename attachment, style_name
|
38
|
+
"#{basename(attachment, style_name)}.#{extension(attachment, style_name)}"
|
39
39
|
end
|
40
40
|
|
41
41
|
# Returns the interpolated URL. Will raise an error if the url itself
|
42
42
|
# contains ":url" to prevent infinite recursion. This interpolation
|
43
43
|
# is used in the default :path to ease default specifications.
|
44
|
-
def url attachment,
|
44
|
+
def url attachment, style_name
|
45
45
|
raise InfiniteInterpolationError if attachment.options[:url].include?(":url")
|
46
|
-
attachment.url(
|
46
|
+
attachment.url(style_name, false)
|
47
47
|
end
|
48
48
|
|
49
49
|
# Returns the timestamp as defined by the <attachment>_updated_at field
|
50
|
-
def timestamp attachment,
|
50
|
+
def timestamp attachment, style_name
|
51
51
|
attachment.instance_read(:updated_at).to_s
|
52
52
|
end
|
53
53
|
|
54
54
|
# Returns the RAILS_ROOT constant.
|
55
|
-
def rails_root attachment,
|
55
|
+
def rails_root attachment, style_name
|
56
56
|
RAILS_ROOT
|
57
57
|
end
|
58
58
|
|
59
59
|
# Returns the RAILS_ENV constant.
|
60
|
-
def rails_env attachment,
|
60
|
+
def rails_env attachment, style_name
|
61
61
|
RAILS_ENV
|
62
62
|
end
|
63
63
|
|
64
64
|
# Returns the underscored, pluralized version of the class name.
|
65
65
|
# e.g. "users" for the User class.
|
66
|
-
|
66
|
+
# NOTE: The arguments need to be optional, because some tools fetch
|
67
|
+
# all class names. Calling #class will return the expected class.
|
68
|
+
def class attachment = nil, style_name = nil
|
69
|
+
return super() if attachment.nil? && style_name.nil?
|
67
70
|
attachment.instance.class.to_s.underscore.pluralize
|
68
71
|
end
|
69
72
|
|
70
73
|
# Returns the basename of the file. e.g. "file" for "file.jpg"
|
71
|
-
def basename attachment,
|
74
|
+
def basename attachment, style_name
|
72
75
|
attachment.original_filename.gsub(/#{File.extname(attachment.original_filename)}$/, "")
|
73
76
|
end
|
74
77
|
|
75
78
|
# Returns the extension of the file. e.g. "jpg" for "file.jpg"
|
76
79
|
# If the style has a format defined, it will return the format instead
|
77
80
|
# of the actual extension.
|
78
|
-
def extension attachment,
|
79
|
-
((style = attachment.styles[
|
81
|
+
def extension attachment, style_name
|
82
|
+
((style = attachment.styles[style_name]) && style[:format]) ||
|
80
83
|
File.extname(attachment.original_filename).gsub(/^\.+/, "")
|
81
84
|
end
|
82
85
|
|
83
86
|
# Returns the id of the instance.
|
84
|
-
def id attachment,
|
87
|
+
def id attachment, style_name
|
85
88
|
attachment.instance.id
|
86
89
|
end
|
87
90
|
|
88
91
|
# Returns the id of the instance in a split path form. e.g. returns
|
89
92
|
# 000/001/234 for an id of 1234.
|
90
|
-
def id_partition attachment,
|
93
|
+
def id_partition attachment, style_name
|
91
94
|
("%09d" % attachment.instance.id).scan(/\d{3}/).join("/")
|
92
95
|
end
|
93
96
|
|
94
97
|
# Returns the pluralized form of the attachment name. e.g.
|
95
98
|
# "avatars" for an attachment of :avatar
|
96
|
-
def attachment attachment,
|
99
|
+
def attachment attachment, style_name
|
97
100
|
attachment.name.to_s.downcase.pluralize
|
98
101
|
end
|
99
102
|
|
100
103
|
# Returns the style, or the default style if nil is supplied.
|
101
|
-
def style attachment,
|
102
|
-
|
104
|
+
def style attachment, style_name
|
105
|
+
style_name || attachment.default_style
|
103
106
|
end
|
104
107
|
end
|
105
108
|
end
|