Skip to content
This repository
Browse code

Add AttachmentContentTypeValidator

  • Loading branch information...
commit da5d716b97036dc8bffb3c3ff7a4876957fa7154 1 parent ee42b19
Prem Sichanugrist authored March 16, 2012
34  lib/paperclip.rb
@@ -195,40 +195,6 @@ def has_attached_file(name, options = {})
195 195
       end
196 196
     end
197 197
 
198  
-    # Places ActiveRecord-style validations on the content type of the file
199  
-    # assigned. The possible options are:
200  
-    # * +content_type+: Allowed content types.  Can be a single content type
201  
-    #   or an array.  Each type can be a String or a Regexp. It should be
202  
-    #   noted that Internet Explorer uploads files with content_types that you
203  
-    #   may not expect. For example, JPEG images are given image/pjpeg and
204  
-    #   PNGs are image/x-png, so keep that in mind when determining how you
205  
-    #   match.  Allows all by default.
206  
-    # * +message+: The message to display when the uploaded file has an invalid
207  
-    #   content type.
208  
-    # * +if+: A lambda or name of an instance method. Validation will only
209  
-    #   be run is this lambda or method returns true.
210  
-    # * +unless+: Same as +if+ but validates if lambda or method returns false.
211  
-    # NOTE: If you do not specify an [attachment]_content_type field on your
212  
-    # model, content_type validation will work _ONLY upon assignment_ and
213  
-    # re-validation after the instance has been reloaded will always succeed.
214  
-    # You'll still need to have a virtual attribute (created by +attr_accessor+)
215  
-    # name +[attachment]_content_type+ to be able to use this validator.
216  
-    def validates_attachment_content_type name, options = {}
217  
-      validation_options = options.dup
218  
-      allowed_types = [validation_options[:content_type]].flatten
219  
-      validates_each(:"#{name}_content_type", validation_options) do |record, attr, value|
220  
-        if !allowed_types.any?{|t| t === value } && !(value.nil? || value.blank?)
221  
-          if record.errors.method(:add).arity == -2
222  
-            message = options[:message] || "is not one of #{allowed_types.join(", ")}"
223  
-            message = message.call if message.respond_to?(:call)
224  
-            record.errors.add(:"#{name}_content_type", message)
225  
-          else
226  
-            record.errors.add(:"#{name}_content_type", :inclusion, :default => options[:message], :value => value)
227  
-          end
228  
-        end
229  
-      end
230  
-    end
231  
-
232 198
     # Returns the attachment definitions defined by each call to
233 199
     # has_attached_file.
234 200
     def attachment_definitions
1  lib/paperclip/validators.rb
... ...
@@ -1,4 +1,5 @@
1 1
 require 'active_support/concern'
  2
+require 'paperclip/validators/attachment_content_type_validator'
2 3
 require 'paperclip/validators/attachment_presence_validator'
3 4
 require 'paperclip/validators/attachment_size_validator'
4 5
 
45  lib/paperclip/validators/attachment_content_type_validator.rb
... ...
@@ -0,0 +1,45 @@
  1
+module Paperclip
  2
+  module Validators
  3
+    class AttachmentContentTypeValidator < ActiveModel::EachValidator
  4
+      def validate_each(record, attribute, value)
  5
+        attribute = "#{attribute}_content_type".to_sym
  6
+        value = record.send(:read_attribute_for_validation, attribute)
  7
+        allowed_types = [options[:content_type]].flatten
  8
+
  9
+        unless value.blank?
  10
+          allowed_types.any? do |type|
  11
+            unless type === value
  12
+              record.errors.add(attribute, :invalid, options.merge(
  13
+                :types => allowed_types.join(', ')
  14
+              ))
  15
+            end
  16
+          end
  17
+        end
  18
+      end
  19
+    end
  20
+
  21
+    module HelperMethods
  22
+      # Places ActiveRecord-style validations on the content type of the file
  23
+      # assigned. The possible options are:
  24
+      # * +content_type+: Allowed content types.  Can be a single content type
  25
+      #   or an array.  Each type can be a String or a Regexp. It should be
  26
+      #   noted that Internet Explorer uploads files with content_types that you
  27
+      #   may not expect. For example, JPEG images are given image/pjpeg and
  28
+      #   PNGs are image/x-png, so keep that in mind when determining how you
  29
+      #   match.  Allows all by default.
  30
+      # * +message+: The message to display when the uploaded file has an invalid
  31
+      #   content type.
  32
+      # * +if+: A lambda or name of an instance method. Validation will only
  33
+      #   be run is this lambda or method returns true.
  34
+      # * +unless+: Same as +if+ but validates if lambda or method returns false.
  35
+      # NOTE: If you do not specify an [attachment]_content_type field on your
  36
+      # model, content_type validation will work _ONLY upon assignment_ and
  37
+      # re-validation after the instance has been reloaded will always succeed.
  38
+      # You'll still need to have a virtual attribute (created by +attr_accessor+)
  39
+      # name +[attachment]_content_type+ to be able to use this validator.
  40
+      def validates_attachment_content_type(*attr_names)
  41
+        validates_with AttachmentContentTypeValidator, _merge_attributes(attr_names)
  42
+      end
  43
+    end
  44
+  end
  45
+end
15  test/paperclip_test.rb
@@ -329,21 +329,6 @@ def self.should_validate validation, options, valid_file, invalid_file
329 329
       should_validate validation, options, valid_file, invalid_file
330 330
     end
331 331
 
332  
-    context "with content_type validation and lambda message" do
333  
-      context "and assigned an invalid file" do
334  
-        setup do
335  
-          Dummy.send(:"validates_attachment_content_type", :avatar, :content_type => %r{image/.*}, :message => lambda {'lambda content type message'})
336  
-          @dummy = Dummy.new
337  
-          @dummy.avatar &&= File.open(File.join(FIXTURES_DIR, "text.txt"), "rb")
338  
-          @dummy.valid?
339  
-        end
340  
-
341  
-        should "have a content type error message" do
342  
-          assert [@dummy.errors[:avatar_content_type]].flatten.any?{|error| error =~ %r/lambda content type message/ }
343  
-        end
344  
-      end
345  
-    end
346  
-
347 332
     context "with size validation and less_than 10240 option" do
348 333
       context "and assigned an invalid file" do
349 334
         setup do
106  test/validators/attachment_content_type_validator_test.rb
... ...
@@ -0,0 +1,106 @@
  1
+require './test/helper'
  2
+
  3
+class AttachmentContentTypeValidatorTest < Test::Unit::TestCase
  4
+  def setup
  5
+    rebuild_model
  6
+    @dummy = Dummy.new
  7
+  end
  8
+
  9
+  def build_validator(options)
  10
+    @validator = Paperclip::Validators::AttachmentContentTypeValidator.new(options.merge(
  11
+      :attributes => :avatar
  12
+    ))
  13
+  end
  14
+
  15
+  context "with a nil content type" do
  16
+    setup do
  17
+      build_validator :content_type => "image/jpg"
  18
+      @dummy.stubs(:avatar_content_type => nil)
  19
+      @validator.validate(@dummy)
  20
+    end
  21
+
  22
+    should "not set an error message" do
  23
+      assert @dummy.errors[:avatar_content_type].blank?
  24
+    end
  25
+  end
  26
+
  27
+  context "with an allowed type" do
  28
+    context "as a string" do
  29
+      setup do
  30
+        build_validator :content_type => "image/jpg"
  31
+        @dummy.stubs(:avatar_content_type => "image/jpg")
  32
+        @validator.validate(@dummy)
  33
+      end
  34
+
  35
+      should "not set an error message" do
  36
+        assert @dummy.errors[:avatar_content_type].blank?
  37
+      end
  38
+    end
  39
+
  40
+    context "as an regexp" do
  41
+      setup do
  42
+        build_validator :content_type => /^image\/.*/
  43
+        @dummy.stubs(:avatar_content_type => "image/jpg")
  44
+        @validator.validate(@dummy)
  45
+      end
  46
+
  47
+      should "not set an error message" do
  48
+        assert @dummy.errors[:avatar_content_type].blank?
  49
+      end
  50
+    end
  51
+  end
  52
+
  53
+  context "with a disallowed type" do
  54
+    context "as a string" do
  55
+      setup do
  56
+        build_validator :content_type => "image/png"
  57
+        @dummy.stubs(:avatar_content_type => "image/jpg")
  58
+        @validator.validate(@dummy)
  59
+      end
  60
+
  61
+      should "set a correct default error message" do
  62
+        assert @dummy.errors[:avatar_content_type].present?
  63
+        assert_includes @dummy.errors[:avatar_content_type], "is invalid"
  64
+      end
  65
+    end
  66
+
  67
+    context "as a regexp" do
  68
+      setup do
  69
+        build_validator :content_type => /^text\/.*/
  70
+        @dummy.stubs(:avatar_content_type => "image/jpg")
  71
+        @validator.validate(@dummy)
  72
+      end
  73
+
  74
+      should "set a correct default error message" do
  75
+        assert @dummy.errors[:avatar_content_type].present?
  76
+        assert_includes @dummy.errors[:avatar_content_type], "is invalid"
  77
+      end
  78
+    end
  79
+
  80
+    context "with :message option" do
  81
+      context "without interpolation" do
  82
+        setup do
  83
+          build_validator :content_type => "image/png", :message => "should be a PNG image"
  84
+          @dummy.stubs(:avatar_content_type => "image/jpg")
  85
+          @validator.validate(@dummy)
  86
+        end
  87
+
  88
+        should "set a correct error message" do
  89
+          assert_includes @dummy.errors[:avatar_content_type], "should be a PNG image"
  90
+        end
  91
+      end
  92
+
  93
+      context "with interpolation" do
  94
+        setup do
  95
+          build_validator :content_type => "image/png", :message => "should have content type %{types}"
  96
+          @dummy.stubs(:avatar_content_type => "image/jpg")
  97
+          @validator.validate(@dummy)
  98
+        end
  99
+
  100
+        should "set a correct error message" do
  101
+          assert_includes @dummy.errors[:avatar_content_type], "should have content type image/png"
  102
+        end
  103
+      end
  104
+    end
  105
+  end
  106
+end

0 notes on commit da5d716

Please sign in to comment.
Something went wrong with that request. Please try again.