2 module Validations #:nodoc:
4 def self.append_features(base)
6 base.extend(ClassMethods)
9 # This module contains methods to create validations of uploaded files. All methods
10 # in this module will be included as class methods into <tt>ActiveRecord::Base</tt>
11 # so that you can use them in your models like this:
13 # class Entry < ActiveRecord::Base
15 # validates_filesize_of :image, :in => 0..1.megabyte
18 EXT_REGEXP = /\.([A-z0-9]+)$/
20 # This validates the file type of one or more file_columns. A list of file columns
21 # should be given followed by an options hash.
24 # * <tt>:in</tt> => list of extensions or mime types. If mime types are used they
25 # will be mapped into an extension via FileColumn::ClassMethods::MIME_EXTENSIONS.
28 # validates_file_format_of :field, :in => ["gif", "png", "jpg"]
29 # validates_file_format_of :field, :in => ["image/jpeg"]
30 def validates_file_format_of(*attrs)
32 options = attrs.pop if attrs.last.is_a?Hash
33 raise ArgumentError, "Please include the :in option." if !options || !options[:in]
34 options[:in] = [options[:in]] if options[:in].is_a?String
35 raise ArgumentError, "Invalid value for option :in" unless options[:in].is_a?Array
37 validates_each(attrs, options) do |record, attr, value|
39 mime_extensions = record.send("#{attr}_options")[:mime_extensions]
40 extensions = options[:in].map{|o| mime_extensions[o] || o }
41 record.errors.add attr, "is not a valid format." unless extensions.include?(value.scan(EXT_REGEXP).flatten.first)
47 # This validates the file size of one or more file_columns. A list of file columns
48 # should be given followed by an options hash.
51 # * <tt>:in</tt> => A size range. Note that you can use ActiveSupport's
52 # numeric extensions for kilobytes, etc.
55 # validates_filesize_of :field, :in => 0..100.megabytes
56 # validates_filesize_of :field, :in => 15.kilobytes..1.megabyte
57 def validates_filesize_of(*attrs)
59 options = attrs.pop if attrs.last.is_a?Hash
60 raise ArgumentError, "Please include the :in option." if !options || !options[:in]
61 raise ArgumentError, "Invalid value for option :in" unless options[:in].is_a?Range
63 validates_each(attrs, options) do |record, attr, value|
65 size = File.size(value)
66 record.errors.add attr, "is smaller than the allowed size range." if size < options[:in].first
67 record.errors.add attr, "is larger than the allowed size range." if size > options[:in].last
73 IMAGE_SIZE_REGEXP = /^(\d+)x(\d+)$/
75 # Validates the image size of one or more file_columns. A list of file columns
76 # should be given followed by an options hash. The validation will pass
77 # if both image dimensions (rows and columns) are at least as big as
78 # given in the <tt>:min</tt> option.
81 # * <tt>:min</tt> => minimum image dimension string, in the format NNxNN
85 # validates_image_size :field, :min => "1200x1800"
87 # This validation requires RMagick to be installed on your system
88 # to check the image's size.
89 def validates_image_size(*attrs)
90 options = attrs.pop if attrs.last.is_a?Hash
91 raise ArgumentError, "Please include a :min option." if !options || !options[:min]
92 minimums = options[:min].scan(IMAGE_SIZE_REGEXP).first.collect{|n| n.to_i} rescue []
93 raise ArgumentError, "Invalid value for option :min (should be 'XXxYY')" unless minimums.size == 2
97 validates_each(attrs, options) do |record, attr, value|
100 img = ::Magick::Image::read(value).first
101 record.errors.add('image', "is too small, must be at least #{minimums[0]}x#{minimums[1]}") if ( img.rows < minimums[1] || img.columns < minimums[0] )
102 rescue ::Magick::ImageMagickError
103 record.errors.add('image', "invalid image")