user664833
user664833

Reputation: 19505

How to validate a file extension only if there is a file extension? Re: carrierwave

I am using CarrierWave, and I would like to validate file names and only allow file uploads if the extension is .gif, .png, .jpg, .jpeg, or if there is no file extension.

Sometimes users upload files with no extensions. For example:

http://t2.gstatic.com/images?q=tbn:ANd9GcTCD2TLvYI8a4ChgBaYK_JaRfedvXLr3HXQfj0arXXAii3o2yjf

I am aware of the possibility of uncommenting the following lines in uploaders/image_uploader.rb, but I don't know of a way of additionally saying "allow any of these extensions only if there is a file extension".

# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
#def extension_white_list
#  %w(gif jpg jpeg png)
#end

As well, in my model I have a validation as follows, but for some reason bad-extension.bad passes.

validates :image, allow_blank: true, format: {
    with: %r{\.(gif|jpe?g|png)\z}i,
    message: 'must be a GIF, JPG, or PNG'
}, if: :filename_has_extension?

def filename_has_extension?
  image =~ /\./
end

Upvotes: 7

Views: 4746

Answers (3)

m1l05z
m1l05z

Reputation: 378

in my case I just change in my avatar_uploader.rb:

  def extension_white_list
    %w(jpg jpeg gif png) if model.avatar.file.extension.present?
  end

:)

Upvotes: 0

Viren
Viren

Reputation: 5962

Well Why not use Mimetype comparison of the file in validation process there is ruby gem call mimetype that can help you in your quest

something like this

AVAILABLE_MIMETYPE = %w(image/gif)

validate :mime_type_of ,:if => :if_changed?


private
def mime_type_of
  AVAILABLE::MIMETYPE.include?(MIME::Types.type_for[image_path][0]) 
end

def if_changed?
  new_record? or image_changed?
end

Even CarrierWave Include MimeType Gem Internally check if that can help too

Hope this Help

Upvotes: 2

user664833
user664833

Reputation: 19505

image is not a String, rather it's of the class ImageUploader (class ImageUploader < CarrierWave::Uploader::Base).

Therefore this line is at fault:

image =~ /\./

Correct it by converting it to a String:

image.to_s =~ /\./

That said, a better expression would be:

!(image.to_s =~ /\.[a-z]{1,4}\z/).nil?

It makes sure that the extension consists of one to four a-z characters. Also, =~ returns nil if nothing is found, and this line takes that into account.

If an extension is not found, =~ returns nil; so .nil? will return true; and ! will invert it to false; thus indicating that there is no extension.

If on the other hand there is an extension, =~ returns the position the match starts; which is 0 or greater, which is not nil; so .nil? will return false; and when inverted by !, true is returned; thus indicating that there is an extension.

Upvotes: 0

Related Questions