yurko
8/14/2016 - 7:59 PM

Rails - Carrierwave validation of image size

Rails - Carrierwave validation of image size

class Model < ActiveRecord::Base
  mount_uploader :image, BaseUploader
  
  validates :image, image_size: { width: { min: 1024 }, height: { in: 200..500 } }
  
  ...
end
class ImageSizeValidator < ActiveModel::EachValidator

  def initialize(options)
    [:width, :height].each do |length|
      if options[length] and options[length].is_a?(Hash)
        if range = (options[length].delete(:in) || options[length].delete(:within))
          raise ArgumentError, ":in and :within must be a Range" unless range.is_a?(Range)
          options[length][:min], options[length][:max] = range.min, range.max
        end
      end
    end
    super
  end

  def validate_each(record, attribute, value)
    unless record.send("#{attribute}_cache").nil?
      [:width, :height].each do |length|
        if options[length]
          if options[length].is_a?(Hash)
            if (options[length][:min] && record.send(attribute).send(length) < options[length][:min])
              record.errors[attribute] << I18n.t("activerecord.errors.messages.image.greater_than_or_equal_to", length: length, count: options[length][:min])
            end
            if (options[length][:max] && record.send(attribute).send(length) > options[length][:max])
              record.errors[attribute] << I18n.t("activerecord.errors.messages.image.less_than_or_equal_to", length: length, count: options[length][:max])
            end
          else
            if (record.send(attribute).send(length) != options[length])
              record.errors[attribute] << I18n.t("activerecord.errors.messages.image.equal_to", length: length, count: options[length])
            end
          end
        end
      end
    end
  end

end
---
en-US:
  activerecord:
     errors:
      messages:
        image:
          equal_to: "%{length} must be equal to %{count} pixels"
          greater_than_or_equal_to: "%{length} must be greater or equal to %{count} pixels"
          less_than_or_equal_to: "%{length} must be less than or equal to %{count} pixels"
class BaseUploader < CarrierWave::Uploader::Base
    attr_reader :width, :height
    before :cache, :capture_size
    
    ...
    
    # for image size validation
    # fetching dimensions in uploader, validating it in model
    def capture_size(file)
      if version_name.blank? # Only do this once, to the original version
        if file.path.nil? # file sometimes is in memory
          img = ::MiniMagick::Image::read(file.file)
          @width = img[:width]
          @height = img[:height]
        else
          @width, @height = `identify -format "%wx %h" #{file.path}`.split(/x/).map{|dim| dim.to_i }
        end
      end
    end
  end
end