lib/attached.rb in attached-0.5.2 vs lib/attached.rb in attached-0.5.3
- old
+ new
@@ -1,34 +1,34 @@
require 'attached/attachment'
require 'attached/railtie'
-module Attached
-
-
+module Attached
+
+
def self.included(base)
base.extend ClassMethods
base.class_attribute :attached_options
end
-
-
+
+
module Definition
def attachment(*args)
options = args.extract_options!
-
+
args.each do |name|
column("#{name}_identifier", :string, options)
column("#{name}_extension", :string, options)
column("#{name}_size", :integer, options)
end
end
end
-
-
+
+
module ClassMethods
-
-
+
+
# Add an attachment to a class.
#
# Options:
#
# * :styles - a hash containing style names followed by parameters passed to processor
@@ -38,236 +38,236 @@
# Usage:
#
# has_attached :video
# has_attached :video, :storage => :aws
# has_attached :video, styles => { :mov => { :size => "480p", :format => "mov" } }
-
+
def has_attached(name, options = {})
-
+
include InstanceMethods
-
+
self.attached_options ||= {}
self.attached_options[name] = options
-
+
before_save :save_attached
before_destroy :destroy_attached
-
+
define_method name do
attachment_for(name)
end
-
+
define_method "#{name}=" do |file|
attachment_for(name).assign(file)
end
define_method "#{name}?" do
attachment_for(name).attached?
end
-
+
validates_each(name) do |record, attr, value|
attachment = record.attachment_for(name)
attachment.errors.each do |error|
record.errors.add(name, error)
end
end
-
+
after_validation do
-
+
if self.errors.include?(:"#{name}_size")
self.errors[:"#{name}_size"].each do |message|
self.errors.add(name, message)
end
self.errors[:"#{name}_size"].clear
end
-
+
if self.errors.include?(:"#{name}_extension")
self.errors[:"#{name}_extension"].each do |message|
self.errors.add(name, message)
end
self.errors[:"#{name}_extension"].clear
end
-
+
if self.errors.include?(:"#{name}_identifier")
self.errors[:"#{name}_identifier"].each do |message|
self.errors.add(name, message)
end
self.errors[:"#{name}_identifier"].clear
end
-
+
end
-
+
end
-
-
- # Validates an attached size in a specified range or minimum and maximum.
+
+
+ # Validates an attached size in a specified range or minimum and maximum.
#
# Options:
#
# * :message - string to be displayed with :minimum and :maximum variables
# * :minimum - integer for the minimum byte size of the attached
# * :maximum - integer for the maximum byte size of teh attached
# * :in - range of bytes for file
#
# Usage:
- #
+ #
# validates_attached_size :avatar, :range => 10.megabytes .. 20.megabytes
# validates_attached_size :avatar, :minimum => 10.megabytes, :maximum => 20.megabytes
# validates_attached_size :avatar, :message => "size must be between :minimum and :maximum bytes"
-
+
def validates_attached_size(name, options = {})
-
+
zero = (0.0 / 1.0)
infi = (1.0 / 0.0)
-
+
minimum = options[:minimum] || options[:in] && options[:in].first || zero
maximum = options[:maximum] || options[:in] && options[:in].last || infi
-
+
message = options[:message]
message ||= "size must be specified" if minimum == zero && maximum == infi
message ||= "size must be a minimum of :minimum" if maximum == infi
message ||= "size must be a maximum of :maximum" if minimum == zero
message ||= "size must be between :minimum and :maximum"
-
+
range = minimum..maximum
-
+
message.gsub!(/:minimum/, number_to_size(minimum)) unless minimum == zero
message.gsub!(/:maximum/, number_to_size(maximum)) unless maximum == infi
-
- validates_inclusion_of :"#{name}_size", :in => range, :message => message,
+
+ validates_inclusion_of :"#{name}_size", :in => range, :message => message,
:if => options[:if], :unless => options[:unless]
-
+
end
-
-
- # Validates an attached extension in a specified set.
+
+
+ # Validates an attached extension in a specified set.
#
# Options:
#
# * :in - allowed values for attached
#
# Usage:
- #
+ #
# validates_attached_extension :avatar, :is => 'png'
# validates_attached_extension :avatar, :in => %w(png jpg)
# validates_attached_extension :avatar, :in => [:png, :jpg]
# validates_attached_extension :avatar, :in => %w(png jpg), :message => "extension must be :in"
# validates_attached_extension :avatar, :in => %w(png jpg), :message => "extension must be :in"
-
+
def validates_attached_extension(name, options = {})
-
+
message = options[:message]
message ||= "extension is invalid"
-
+
options[:in] ||= [options[:is]] if options[:is]
-
+
range = options[:in].map { |element| ".#{element}" }
-
+
validates_inclusion_of :"#{name}_extension", :in => range, :message => message,
:if => options[:if], :unless => options[:unless]
end
-
-
+
+
# Validates that an attachment is included.
#
# Options:
#
# * :message - string to be displayed
#
# Usage:
#
# validates_attached_presence :avatar
# validates_attached_presence :avatar, :message => "must be attached"
-
+
def validates_attached_presence(name, options = {})
-
+
message = options[:message]
message ||= "must be attached"
-
+
validates_presence_of :"#{name}_identifier", :message => message,
:if => options[:if], :unless => options[:unless]
-
+
end
-
-
+
+
private
-
-
+
+
# Convert a number to a human readable size.
#
# Usage:
#
# number_to_size(1) # 1 byte
# number_to_size(2) # 2 bytes
# number_to_size(1024) # 1 kilobyte
# number_to_size(2048) # 2 kilobytes
-
+
def number_to_size(number, options = {})
return if number == 0.0 / 1.0
return if number == 1.0 / 0.0
-
+
singular = options['singular'] || 1
base = options['base'] || 1024
units = options['units'] || ["byte", "kilobyte", "megabyte", "gigabyte", "terabyte", "petabyte"]
-
+
exponent = (Math.log(number) / Math.log(base)).floor
-
+
number /= base ** exponent
unit = units[exponent]
-
+
number == singular ? unit.gsub!(/s$/, '') : unit.gsub!(/$/, 's')
-
+
"#{number} #{unit}"
end
-
-
+
+
end
-
-
+
+
module InstanceMethods
-
-
+
+
# Create or access attachment.
#
# Usage:
- #
+ #
# attachment_for :avatar
-
+
def attachment_for(name)
@_attached_attachments ||= {}
@_attached_attachments[name] ||= Attachment.new(name, self, self.class.attached_options[name])
end
-
-
+
+
# Log and save all attached (using specified storage).
#
# Usage:
#
# before_save :save_attached
-
+
def save_attached
logger.info "[attached] save attached"
-
- self.class.attached_options.each do |name, options|
+
+ self.class.attached_options.each do |name, options|
attachment_for(name).save
end
end
-
-
+
+
# Log and destroy all attached (using specified storage).
#
# Usage:
#
# before_save :destroy_attached
-
+
def destroy_attached
logger.info "[attached] destroy attached"
-
+
self.class.attached_options.each do |name, options|
attachment_for(name).destroy
end
end
-
-
+
+
end
-
-
+
+
end
\ No newline at end of file