Skip to content

Instantly share code, notes, and snippets.

@lou
Last active March 22, 2022 11:59
Show Gist options
  • Save lou/2881f1aa183078687f1e to your computer and use it in GitHub Desktop.
Save lou/2881f1aa183078687f1e to your computer and use it in GitHub Desktop.
Rails - Carrierwave validation of image size
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
---
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 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
class Model < ActiveRecord::Base
mount_uploader :image, BaseUploader
validates :image, image_size: { width: { min: 1024 }, height: { in: 200..500 } }
...
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment