Embed URL


SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

A cheap knock off of the default validates_length_of validator, but checks the filesize of a Carrierwave attachment


Note that this validation runs both after the file is uploaded and after CarrierWave has processed the image. If your base uploader includes a filter to resize the image then the validation will be run against the resized image, not the original one that was uploaded. If this causes a problem for you, then you should avoid using a resizing filter on the base uploader and put any specific size requirements in a version instead.

So instead of this:

require 'carrierwave/processing/mini_magick'

class LogoUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  process :quality => 80
  process :resize_to_limit => [800, 800]
  process :convert => 'png'

  # ...

Do this:

require 'carrierwave/processing/mini_magick'

class LogoUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  process :convert => 'png'

  version :medium do
    process :quality => 80
    process :resize_to_limit => [800, 800]

  # ...

1 2 3 4 5 6 7
# config/locales/en.yml
wrong_size: "is the wrong size (should be %{file_size})"
size_too_small: "is too small (should be at least %{file_size})"
size_too_big: "is too big (should be at most %{file_size})"
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
# lib/file_size_validator.rb
# Based on:
class FileSizeValidator < ActiveModel::EachValidator
MESSAGES = { :is => :wrong_size, :minimum => :size_too_small, :maximum => :size_too_big }.freeze
CHECKS = { :is => :==, :minimum => :>=, :maximum => :<= }.freeze
DEFAULT_TOKENIZER = lambda { |value| value.split(//) }
RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long]
def initialize(options)
if range = (options.delete(:in) || options.delete(:within))
raise ArgumentError, ":in and :within must be a Range" unless range.is_a?(Range)
options[:minimum], options[:maximum] = range.begin, range.end
options[:maximum] -= 1 if range.exclude_end?
def check_validity!
keys = CHECKS.keys & options.keys
if keys.empty?
raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
keys.each do |key|
value = options[key]
unless value.is_a?(Integer) && value >= 0
raise ArgumentError, ":#{key} must be a nonnegative Integer"
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)
CHECKS.each do |key, validity_check|
next unless check_value = options[key]
value ||= [] if key == :maximum
value_size = value.size
next if value_size.send(validity_check, check_value)
errors_options = options.except(*RESERVED_OPTIONS)
errors_options[:file_size] = help.number_to_human_size check_value
default_message = options[MESSAGES[key]]
errors_options[:message] ||= default_message if default_message
record.errors.add(attribute, MESSAGES[key], errors_options)
def help
class Helper
include Singleton
include ActionView::Helpers::NumberHelper

In your en.yml you spelled "too" wrong twice.


Fixed, thanks!

No worries, thank you for the validator :)

Is this before or after upload? Does it wait until the 10GB file has uploaded to say it's too big?

After upload. Carrierwave wouldn't be able to report the real file size until it was fully uploaded. AFAIK browsers don't send file size info and if they did it could easily be spoofed.

Ok thank you, maybe I can have it timeout if it goes too long.

You may try asking about this on I think it's a good question of whether there is a reliable way of doing this before uploading. One thing I can think of is maybe some kind of flash uploader component that would be able to read the file being selected, check the file size, maybe make a query to the server for any other requirements, and do some pre-validation on the client side before the form is submitted. Let me know how you make out, I'm interested in hearing if there is a solution.

On the other hand, it's really only the user that is inconvenienced if they try to upload something that is 10GB when a smaller limit is clearly stated.

Thanks for your help. I just worry about tying up resources.

Having trouble getting this to work. I've added the class to lib, restarted my rails server, and am still able to upload a 5MB file with validates :picture, file_size: { maximum: 4.megabytes }


@emilford - It should be defined like this:

validates :picture,
  :file_size => { 
    :maximum => 4.megabytes.to_i

Both syntaxes work...what I had was just the new 1.9.x hash syntax. I just noticed that a resize_to_fill was dropping my 5MB file in size, so the validation was never hit. Thanks for this.

where can i find a validator for mongoid? Thank you

Thanks man. Worked perfect

@hyperrjas This validator works for me with mongoid.
@chrisbloom7 Thank you

@ruseel For me it does not works for mongoid: I have in model:

require 'file_size_validator'
class Post
  include Mongoid::Document
  mount_uploader :posted, PostedUploader, mount_on: :posted_filename
  field :posted
  field :posted_cache
  field :remove_posted
  field :remote_posted_url
  validates :posted, :presence => true, :file_size => { :maximum => 0.5.megabytes.to_i  } 

and I upload since my pc with 5 mb for example, and the image its uploaded with 5 mb size.

I have in my posted_uploader.rb

require 'carrierwave/processing/mini_magick'
class PostedUploader < CarrierWave::Uploader::Base
 include CarrierWave::MiniMagick
 storage :grid_fs

 def store_dir

process :resize_to_limit => [560, 560]
process :convert => :png

      version :medium do
        process :resize_to_fit => [200,380]
        process :convert => :png

      version :big do
        process :resize_to_limit => [560, 560]
        process :convert => :png

     version :thumb do
        process :resize_to_fill => [61, 61]
        process :convert => :png

      version :superthumb do
        process :resize_to_fill => [50, 50]
        process :convert => :png

    def extension_white_list
     %w(jpg jpeg gif png)

    def filename
       if not super.nil?
        super.chomp(File.extname(super)) + '.png'


Where is the problem? Why the validate does not works and I can upload image greather than 0.5 mb?

Thank you!

If you need to pass in a method name as the value try this:

@kolaboratory Thank you for this lib, but in my model, with this does not works:

 validates :posted, :file_size => { :maximum => 0.5.megabytes.to_i  } 

What have I that write in my model?

Thank you again!


I have the same issue as @hyperrjas. Added the validator into the /lib folder and getting the following err:
Unknown validator: 'FileSizeValidator'

Using Rails 3.2.1 (i'm new to Rails so this might be something very simple)

My Model code looks like this:

validates :screenshot,
    :presence => true,
    :file_size => {
        :maximum => 5.megabytes.to_i

actually, I just added the YML piece and now I'm getting this ...
"undefined method `key?' for nil:NilClass"

thanks for your help.



@imehesz - did you remember to require the validator in the model file?

require 'file_size_validator'
class Whatever < ActiveRecord::Base

If that's not the solution then you will need to post the full stack trace of the error, including line numbers and file names.


that's what it was! I knew it was something silly.
works like a charm ...



@emilford - thanks for the tip about when the image is validated against. I've added a note to the gist to highlight this issue.

@chrisbloom7, sure thing.

bokor commented

Even through the validation is working, the image is still getting cached for me. Is there anyway around this?


I'm assuming you mean cached as in stored to the temp folder. No there is no way around that as CarrierWave has to store it somewhere first before the file can be available for validation. You could use an after_validation callback to cleanup the temp file if the validation fails, or have a worker process do that periodically on older temp files.

bokor commented


Thanks for getting back to me. Do you know what methods to call to make this happen? I can't seem to figure out how to get those to clean up. I have tried various things and they haven't worked. I would like to encapsulate everything on the Mounted Uploader, but not sure if that would work either.


Before the image is saved the full path to the temp image is stored in the attribute you've mounted the uploader on. So for instance:

 > i =
 => #<Contest > 
 > i.image ='spec', 'support', 'images', '0.5_mb.jpg'))
 => #<File:/Users/chrisbloom7/Projects/foo/spec/support/images/0.5_mb.jpg> 
 > i.image
 => /Users/chrisbloom7/Projects/foo/tmp/uploads/development/20120416-1201-4288-3087/0.5_mb.jpg 

So in your after_validation callback method, check to see if the instance's errors hash contains a key for your mounted attribute, and if so delete the image in the specified path.

bokor commented

Perfect...thank you!


You might also try posting to the CW Google Group to see if the Uploaders have a built in mechanism for handling this.

Hi guys, I get this error for spanish language:

I18n::MissingTranslationData in ItemsController#create
translation missing: es.number.human.storage_units.format

lib/file_size_validator.rb:51:in `block in validate_each'
lib/file_size_validator.rb:42:in `each'
lib/file_size_validator.rb:42:in `validate_each'
app/controllers/items_controller.rb:76:in `block in create'
app/controllers/items_controller.rb:75:in `create'

How can I fix this error for differents languages?
Thank you

ruseel commented

@hyperrjas Try 'rails-i18n' gem in your Gemfile.


Edit: Try @ruseel's suggestion first

@hyperrjas Copy the entries from the config/locales/en.yml file above into config/locales/es.yml and provide the proper translations.

Thank you the @ruseel's suggestion has solved the problem :D. Thank you very much!


Thank you!


I'm getting an exception (unknown validator) when running rspec tests - is there a place I should include the file_size_validator somewhere in rspec? Thanks

I was getting "comparison of String with 0 failed" exception in the line 51 for the values larger then 1023, until I added precision:

errors_options[:file_size] = help.number_to_human_size check_value, :precision => 5

Now it works fine.

Ruby 2.0.0-p247
Rails 3.2.13

why not merge it into CarrierWave? :)

I'm debugging the code because it's giving me undefined method '<=' for nil:NilClass), that's on the line next if value_size.send(validity_check, check_value).
The options I'm passing: validates :profile_img, file_size: {maximum: 2.megabytes.to_i}.

The following 2 lines don't make sense for me:

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)

Maybe I'm missing something, but value cannot be of type Uploader and String at the same time:

> String
=> false 
> "abc".kind_of? CarrierWave::Uploader::Base
=> false 

I discovered this was caused by some coincidence: I was migrating from paperclip and some records already had uploads, so carrierwave was thinking they are valid. I'm hosting on Azure, so I used carrierwave-azure which makes an HTTP request to get the file size and returns nil, instead of 0, if the file is unavailable. The solution was to just clear the outdated values in the upload column. Maybe this helps someone in a similar situation.

Anyway, this validator is almost useless(besides making a human readable file size in the error message), as you can just use the standard Rails length validator.

Works for me the only problem is if the file is too big it ends up saving the file in my application's /uploads/tmp/ directory. Any ideas of how to avoid this from happening and delete the file?

What is the right way to set maximum file size amount for test env?
I did something like this:

file_size: { maximum: (Rails.env.test? ? 1.megabytes.to_i : 5.megabytes.to_i }

but I don't feel it's right.

@saeedSarpas: I'm thinking about this, too. Is there a way to stub the validation within the test itself?

At least, I prettified your code a little:

validates :avatar, file_size: {maximum: (Rails.env.test? ? 5 : 100).kilobytes.to_i}

Hi! I'm using carrierwave and file_size_validator
and I'm using sidekiq
and when I run "bundle exec sidekiq " in console
i see this errors
.../lib/file_size_validator.rb:5: warning: already initialized constant FileSizeValidator::MESSAGES
and the same about

file validators gem does file validations more elegantly. It also supports validations both before and after uploads.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.