Module: Lipsiadmin::DataBase::Attachment::ClassMethods

Defined in:
lib/data_base/attachment.rb

Instance Method Summary collapse

Instance Method Details

#attachment_background_for(name, background) ⇒ Object

When processing, if the spawn plugin is installed, processing can be done in a background fork or thread if desired.



247
248
249
# File 'lib/data_base/attachment.rb', line 247

def attachment_background_for(name, background)
  attachment_definitions[name][:background] = background
end

#attachment_convert_options_for(name, convert_name, convert_options) ⇒ Object

When creating thumbnails, use this free-form options field to pass in various convert command options. Typical options are “-strip” to remove all Exif data from the image (save space for thumbnails and avatars) or “-depth 8” to specify the bit depth of the resulting conversion. See ImageMagick convert documentation for more options: (www.imagemagick.org/script/convert.php) Note that this option takes a hash of options, each of which correspond to the style of thumbnail being generated. You can also specify :all as a key, which will apply to all of the thumbnails being generated. If you specify options for the :original, it would be best if you did not specify destructive options, as the intent of keeping the original around is to regenerate all the thumbnails when requirements change.

attachment_styles          :avatar, :large,    "300x300"
attachment_styles          :avatar, :negative, "100x100"
attachment_convert_options :avatar, :all,      "-strip"
attachment_convert_options :avatar, :negative, "-negate"


240
241
242
243
# File 'lib/data_base/attachment.rb', line 240

def attachment_convert_options_for(name, convert_name, convert_options)
  attachment_definitions[name][:convert_options] ||= {}
  attachment_definitions[name][:convert_options].merge!(convert_name => convert_options)
end

#attachment_default_style_for(name, default_style) ⇒ Object

The thumbnail style that will be used by default URLs. Defaults to original.

attachment_styles :avatar, :normal, "100x100#"
attachment_default_style :normal
user.avatar.url # => "/avatars/23/normal_me.png"


207
208
209
# File 'lib/data_base/attachment.rb', line 207

def attachment_default_style_for(name, default_style)
  attachment_definitions[name][:default_style] = default_style
end

#attachment_default_url_for(name, url) ⇒ Object

The URL that will be returned if there is no attachment assigned. This field is interpolated just as the url is. The default value is

"/images/backend/no-image.png"
has_one_attached_file :avatar
attachment_default_url :avatar, "/images/backend/no-image.png"
User.new.avatar.url(:small) # => "/images/backend/no-image.png"


179
180
181
# File 'lib/data_base/attachment.rb', line 179

def attachment_default_url_for(name, url)
  attachment_definitions[name][:default_url] = url
end

#attachment_definitionsObject

Returns the attachment definitions defined by each call to has_attached_file.



366
367
368
# File 'lib/data_base/attachment.rb', line 366

def attachment_definitions
  read_inheritable_attribute(:attachment_definitions)
end

#attachment_path_for(name, path) ⇒ Object

The path were the attachment are stored. The default value is

:rails_root/public/uploads/:id_:attachment_:style_:basename.:extension

This value must be in consistency with url



187
188
189
# File 'lib/data_base/attachment.rb', line 187

def attachment_path_for(name, path)
  attachment_definitions[name][:path] = path
end

#attachment_processors_for(name, processor_name, processors) ⇒ Object

Attachment supports an extendible selection of post-processors. When you define a set of styles for an attachment, by default it is expected that those “styles” are actually “thumbnails”. However, you can do more than just thumbnail images. By defining a subclass of Lipsiadmin::Attachment::Processor, you can perform any processing you want on the files that are attached. Any file in your Rails app’s lib/attachment_processors directory is automatically loaded by Attachment, allowing you to easily define custom processors. You can specify a processor with the :processors option to has_attached_file:

attachment_styles     :avatar, :text, { :quality => :better }
attachment_processors :avatar, :ocr

This would load the hypothetical class Lipsiadmin::Ocr, which would have the hash “{ :quality => :better }” passed to it along with the uploaded file. For more information about defining processors, see Lipsiadmin::Attachment::Processor.

The default processor is Lipsiadmin::Attachment::Thumbnail. For backwards compatability reasons, you can pass a single geometry string or an array containing a geometry and a format, which the file will be converted to, like so:

attachment_styles     :avatar, :thumb, ["32x32#", :png]

This will convert the “thumb” style to a 32x32 square in png format, regardless of what was uploaded. If the format is not specified, it is kept the same (i.e. jpgs will remain jpgs).

Multiple processors can be specified, and they will be invoked in the order they are defined in the :processors array. Each successive processor will be given the result of the previous processor’s execution. All processors will receive the same parameters, which are what you define in the :styles hash. For example, assuming we had this definition:

attachment_styles     :avatar, :text, { :quality => :better }
attachment_processors :avatar, :rotator
attachment_processors :avatar, :ocr

then both the :rotator processor and the :ocr processor would receive the options “{ :quality => :better }”. This parameter may not mean anything to one or more or the processors, and they are free to ignore it.



290
291
292
293
# File 'lib/data_base/attachment.rb', line 290

def attachment_processors_for(name, processor_name, processors)
  attachment_definitions[name][:processors] ||= {}
  attachment_definitions[name][:processors].merge!(processor_name => processor_processors)
end

#attachment_storage_for(name, storage) ⇒ Object

Chooses the storage backend where the files will be stored. The current choices are :filesystem and :s3. The default is :filesystem. Make sure you read the documentation for Lipsiadmin::Attachment::Storage::Filesystem and Lipsiadmin::Attachment::Storage::S3 for backend-specific options.



222
223
224
# File 'lib/data_base/attachment.rb', line 222

def attachment_storage_for(name, storage)
  attachment_definitions[name][:storage] = storage
end

#attachment_styles_for(name, style_name, styles) ⇒ Object

A hash of thumbnail styles and their geometries. You can find more about geometry strings at the ImageMagick website (www.imagemagick.org/script/command-line-options.php#resize). Attachment also adds the “#” option (e.g. “50x50#”), which will resize the image to fit maximally inside the dimensions and then crop the rest off (weighted at the center). The default value is to generate no thumbnails.



197
198
199
200
# File 'lib/data_base/attachment.rb', line 197

def attachment_styles_for(name, style_name, styles)
  attachment_definitions[name][:styles] ||= {}
  attachment_definitions[name][:styles].merge!(style_name => styles)
end

#attachment_url_for(name, url) ⇒ Object

The full URL of where the attachment is publically accessible. This can just as easily point to a directory served directly through Apache as it can to an action that can control permissions. You can specify the full domain and path, but usually just an absolute path is sufficient. The leading slash must be included manually for absolute paths. The default value is

"/uploads/:id_:attachment_:style_:basename.:extension". See
Lipsiadmin::Attachment::Attach#interpolate for more information on variable interpolaton.
:url => "/:class/:attachment/:id/:style_:basename.:extension"
:url => "http://some.other.host/stuff/:class/:id_:extension"


169
170
171
# File 'lib/data_base/attachment.rb', line 169

def attachment_url_for(name, url)
  attachment_definitions[name][:url] = url
end

#attachment_whiny_for(name, whiny_thumbnails) ⇒ Object

Will raise an error if Attachment cannot post_process an uploaded file due to a command line error. This will override the global setting for this attachment. Defaults to false.



214
215
216
# File 'lib/data_base/attachment.rb', line 214

def attachment_whiny_for(name, whiny_thumbnails)
  attachment_definitions[name][:whiny_thumbnails] = whiny_thumbnails
end

#has_many_attachments(name, options = {}) ⇒ Object

Attach a many files/images to your model.

Examples:

  has_one_attachment                    :images
  attachment_styles_for                 :images, :normal, "128x128!"
  validates_attachment_presence_for     :images
  validates_attachment_size_for         :images, :greater_than => 10.megabytes
  validates_attachment_content_type_for :images, "image/png"

Then in your form (with multipart) you can simply add:

-fields_for "yourmodel[images_attributes][]", @yourmodel.images.build do |image|
  =image.file_field :file


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/data_base/attachment.rb', line 111

def has_many_attachments(name, options = {})
  options[:as]         ||= :attacher
  options[:class_name] ||= "Attachment"

  # We need to check if the attachment model allow multiple attachments
  multi_attachments = options[:class_name].constantize.column_names.include?("attacher_name")

  options[:conditions]   = "attacher_name = '#{name}'" if multi_attachments

  has_many name, options
  before_save "before_save_for_#{name}"
  attr_accessor "#{name}_attributes"

  write_inheritable_attribute(:attachment_definitions, {}) if attachment_definitions.nil?
  attachment_definitions[name] = {:validations => {}}.merge(reflections[name].class_name.constantize.attachment_definitions)

  validates_each(name) do |record, attr, value|
    attributes = record.send("#{name}_attributes")
    attributes ||= {}

    file_column = nil
    for attribute in attributes
      attribute.merge!(:attachment_definitions => record.class.attachment_definitions[name])
      file_column = reflections[name].class_name.constantize.new(attribute)
      unless file_column.valid?
        file_column.errors.each do |error, message|
          record.errors.add(name, message) if message
        end
      end
    end
  end

  define_method "before_save_for_#{name}" do
    attributes = send("#{name}_attributes")
    attributes ||= {}

    file_column = nil

    for attribute in attributes
      next if attribute["file"].blank?
      attribute.merge!(:attachment_definitions => self.class.attachment_definitions[name])
      # We need to add the new attacher_name
      attribute.merge!(:attacher_name => name.to_s) if multi_attachments
      self.send(name).build(attribute)
    end

  end
end

#has_one_attachment(name, options = {}) ⇒ Object

Attach a single file/image to your model.

Examples:

  has_one_attachment                    :image
  attachment_styles_for                 :image, :normal, "128x128!"
  validates_attachment_presence_for     :image
  validates_attachment_size_for         :image, :greater_than => 10.megabytes
  validates_attachment_content_type_for :image, "image/png"

Then in your form (with multipart) you can simply add:

=file_field_tag "yourmodel[image_attributes][file]"

or

-fields_for "yourmodel[image_attributes][file]", @yourmodel.build_image do |image|
  =image.file_field :file


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/data_base/attachment.rb', line 47

def has_one_attachment(name, options={})
  options[:as]         ||= :attacher
  options[:class_name] ||= "Attachment"

  # We need to check if the attachment model allow multiple attachments
  multi_attachments = options[:class_name].constantize.column_names.include?("attacher_name")

  options[:conditions]   = "attacher_name = '#{name}'" if multi_attachments

  has_one name, options
  before_save "before_save_for_#{name}"
  attr_accessor "#{name}_attributes"

  write_inheritable_attribute(:attachment_definitions, {}) if attachment_definitions.nil?
  attachment_definitions[name] = {:validations => {}}.merge(reflections[name].class_name.constantize.attachment_definitions)

  validates_each(name) do |record, attr, value|
    attributes = record.send("#{name}_attributes")
    attributes ||= {}

    attributes.merge!(:attachment_definitions => record.class.attachment_definitions[name])
    file_column = reflections[name].class_name.constantize.new(attributes)
    unless file_column.valid?
      file_column.errors.each do |error, message|
        record.errors.add(name, message) if message
      end
    end
  end

  define_method "before_save_for_#{name}" do
    attributes = send("#{name}_attributes")
    attributes ||= {}

    return if attributes[:file].blank?

    attributes.merge!(:attachment_definitions => self.class.attachment_definitions[name])

    # We need to add the new attacher_name
    attributes.merge!(:attacher_name => name.to_s) if multi_attachments

    if file_column = self.send(name)
      file_column.update_attributes(attributes)
    else
      self.send("build_#{name}", attributes)
    end

  end
end

#validates_attachment_content_type_for(name, *args) ⇒ Object

Places ActiveRecord-style validations on the content type of the file assigned. The possible options are:

  • content_type: Allowed content types. Can be a single content type or an array. Each type can be a String or a Regexp. It should be noted that Internet Explorer upload files with content_types that you may not expect. For example, JPEG images are given image/pjpeg and PNGs are image/x-png, so keep that in mind when determining how you match. Allows all by default.

  • message: The message to display when the uploaded file has an invalid content type.



345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/data_base/attachment.rb', line 345

def validates_attachment_content_type_for(name, *args)
  options = {}
  valid_types = []
  args.each do |variable|
    case variable
      when Hash   then options.merge!(variable)
      else valid_types << variable
    end
  end
  attachment_definitions[name][:validations][:content_type] = lambda do |attachment, instance|
    unless attachment.original_filename.blank?
      content_type = attachment.instance_read(:content_type)
      unless valid_types.any?{ |t| t === content_type }
        options[:message] || I18n.t("activerecord.errors.messages.content_type")
      end
    end
  end
end

#validates_attachment_presence_for(name, options = {}) ⇒ Object

Places ActiveRecord-style validations on the presence of a file.



328
329
330
331
332
333
# File 'lib/data_base/attachment.rb', line 328

def validates_attachment_presence_for(name, options = {})
  message = options[:message] || I18n.t("activerecord.errors.messages.blank")
  attachment_definitions[name][:validations][:presence] = lambda do |attachment, instance|
    message unless attachment.exist?
  end
end

#validates_attachment_size_for(name, options = {}) ⇒ Object

Places ActiveRecord-style validations on the size of the file assigned. The possible options are:

  • in: a Range of bytes (i.e. 1..1.megabyte),

  • less_than: equivalent to :in => 0..options

  • greater_than: equivalent to :in => options..Infinity

  • message: error message to display, use :min and :max as replacements



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/data_base/attachment.rb', line 301

def validates_attachment_size_for(name, options = {})
  min     = options[:greater_than] || (options[:in] && options[:in].first) || 0
  max     = options[:less_than]    || (options[:in] && options[:in].last)  || (1.0/0)
  range   = (min..max)
  helper  = ActionController::Base.helpers

  if options[:message].blank?
    message  = ""
    message << I18n.t("activerecord.errors.messages.greater_than", :count => helper.number_to_human_size(min))    if min > 0
    message << " " + I18n.t("activerecord.errors.messages.less_than", :count => helper.number_to_human_size(max)) if max.to_f.infinite? != 1
  else
    message = options[:message]
  end

  attachment_definitions[name][:validations][:size] = lambda do |attachment, instance|
    if attachment.exist? && !range.include?(attachment.size.to_i)
      message
    end
  end
end

#validates_attachment_thumbnails_for(name, options = {}) ⇒ Object

Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true.



323
324
325
# File 'lib/data_base/attachment.rb', line 323

def validates_attachment_thumbnails_for(name, options = {})
  attachment_definitions[name][:whiny_thumbnails] = true
end