-
-
Save denyago/1298417 to your computer and use it in GitHub Desktop.
en: | |
errors: | |
messages: | |
wrong_content_type: "is the wrong content type" |
# Based on: https://gist.github.com/1009861 | |
class FileMimeTypeValidator < ActiveModel::EachValidator | |
MESSAGES = { :content_type => :wrong_content_type }.freeze | |
CHECKS = [ :content_type ].freeze | |
DEFAULT_TOKENIZER = lambda { |value| value.split(//) } | |
RESERVED_OPTIONS = [:content_type, :tokenizer] | |
def initialize(options) | |
super | |
end | |
def check_validity! | |
keys = CHECKS & options.keys | |
if keys.empty? | |
raise ArgumentError, 'Patterns unspecified. Specify the :content_type option.' | |
end | |
keys.each do |key| | |
value = options[key] | |
unless valid_content_type_option?(value) | |
raise ArgumentError, ":#{key} must be a String or a Regexp or an Array" | |
end | |
if key.is_a?(Array) && key == :content_type | |
options[key].each do |val| | |
raise ArgumentError, "#{val} must be a String or a Regexp" unless val.is_a?(String) || val.is_a?(Regexp) | |
end | |
end | |
end | |
end | |
def validate_each(record, attribute, value) | |
raise(ArgumentError, "A CarrierWave::Uploader::Base object was expected") unless value.kind_of? CarrierWave::Uploader::Base | |
value = (options[:tokenizer] || DEFAULT_TOKENIZER).call(value) if value.kind_of?(String) | |
return if value.length == 0 | |
CHECKS.each do |key| | |
next unless check_value = options[key] | |
if key == :content_type | |
if check_value.is_a?(String) || check_value.is_a?(Regexp) | |
do_validation(value, check_value, key, record, attribute) | |
else | |
check_value.each do |pattern| | |
do_validation(value, pattern, key, record, attribute) | |
end | |
end | |
end | |
end | |
end | |
def help | |
Helper.instance | |
end | |
class Helper | |
include Singleton | |
include ActionView::Helpers::NumberHelper | |
end | |
private | |
def valid_content_type_option?(content_type) | |
return true if %w{Array String Regexp}.include?(content_type.class.to_s) | |
false | |
end | |
def do_validation(value, pattern, key, record, attribute) | |
return if value.file.content_type.send((pattern.is_a?(String) ? "==" : "=~" ), pattern) | |
errors_options = options.except(*RESERVED_OPTIONS) | |
default_message = options[MESSAGES[key]] | |
errors_options[:message] ||= default_message if default_message | |
record.errors.add(attribute, MESSAGES[key], errors_options) | |
end | |
end |
class Post < ActiveRecord::Base | |
mount_uploader :image, ImagePostUploader | |
validates :image, | |
:file_mime_type => { | |
:content_type => /image/ | |
} | |
end |
Thanks for this! It works almost as I hoped. However, whenever I upload an unvalid file it raises ActiveRecord::RecordInvalid exception, instead of the usual flash notice.
Validation failed: Image Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: Command ("identify -ping /var/folders/90/bt4jhsys70d71dfhr06q3crh0000gn/T/mini_magick20130722-17393-19zaaq0.html") failed: {:status_code=>1, :output=>"identify: delegate failed \"html2ps\" -U -o \"%o\" \"%i\"' @ error/delegate.c/InvokeDelegate/1065.\nidentify: unable to open image /var/tmp/magick-17517Qh--EFN7KBBh': No such file or directory @ error/blob.c/OpenBlob/2638.\nidentify: unable to open file /var/tmp/magick-17517Qh--EFN7KBBh': No such file or directory @ error/constitute.c/ReadImage/589.\n"}, Image is the wrong content type
Is it possible to correct this behavior? (I'm a rails newbie and need some points on how to do it myself)
Hi Denis, cool validator thanks for that.
But I use it like this:
validates :icon,
:file_mime_type => {
:content_type => ['image/jpeg', 'image/png', 'image/gif'],
:if => :has_icon?
}
and in this case I've got 2 errors for each of invalid content_type.
that is why I've got update for you:
- def validate_each(record, attribute, value) looks like this for me:
def validate_each(record, attribute, value)
raise(ArgumentError, "A CarrierWave::Uploader::Base object was expected") unless value.kind_of? CarrierWave::Uploader::Base
value = (options[:tokenizer] || DEFAULT_TOKENIZER).call(value) if value.kind_of?(String)
return if value.length == 0
CHECKS.each do |key|
next unless check_value = options[key]
do_validation(value, check_value, key, record, attribute) if key == :content_type
end
end
- and def do_validation(value, pattern, key, record, attribute)
def do_validation(value, pattern, key, record, attribute)
if pattern.is_a?(String) || pattern.is_a?(Regexp)
return if value.file.content_type.send((pattern.is_a?(String) ? "==" : "=~" ), pattern)
else
valid_list = pattern.map do |p|
value.file.content_type.send((p.is_a?(String) ? "==" : "=~" ), p)
end
return if valid_list.include?(true)
end
errors_options = options.except(*RESERVED_OPTIONS)
default_message = options[MESSAGES[key]]
errors_options[:message] ||= default_message if default_message
record.errors.add(attribute, MESSAGES[key], errors_options)
end
Validation logic working fine with me, but the problem is that; active record every time run this validator even when no file is uploaded. So this obviously fails. Is there any way to tackle this situation?