Updating to use Rails 2.1.2. Moving the gem dependancies to the config/environment...
[rails.git] / vendor / plugins / file_column / lib / validations.rb
1 module FileColumn
2   module Validations #:nodoc:
3     
4     def self.append_features(base)
5       super
6       base.extend(ClassMethods)
7     end
8
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:
12     #
13     #    class Entry < ActiveRecord::Base
14     #      file_column :image
15     #      validates_filesize_of :image, :in => 0..1.megabyte
16     #    end
17     module ClassMethods
18       EXT_REGEXP = /\.([A-z0-9]+)$/
19     
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.
22       #
23       # Required options:
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.
26       #
27       # Examples:
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)
31       
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
36       
37         validates_each(attrs, options) do |record, attr, value|
38           unless value.blank?
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)
42           end
43         end
44       
45       end
46     
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.
49       #
50       # Required options:
51       # * <tt>:in</tt> => A size range.  Note that you can use ActiveSupport's
52       #   numeric extensions for kilobytes, etc.
53       #
54       # Examples:
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)  
58       
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
62       
63         validates_each(attrs, options) do |record, attr, value|
64           unless value.blank?
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
68           end
69         end
70       
71       end 
72
73       IMAGE_SIZE_REGEXP = /^(\d+)x(\d+)$/
74
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.
79       #
80       # Required options:
81       # * <tt>:min</tt> => minimum image dimension string, in the format NNxNN
82       #   (columns x rows).
83       #
84       # Example:
85       #    validates_image_size :field, :min => "1200x1800"
86       #
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
94
95         require 'RMagick'
96
97         validates_each(attrs, options) do |record, attr, value|
98           unless value.blank?
99             begin
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")
104             end
105             img = nil
106             GC.start
107           end
108         end
109       end
110     end
111   end
112 end