CarrierWave: Default Configuration and Suggested Changes

Posted About 3 years ago. Visible to the public. Repeats.

CarrierWave comes with a set of default configuration options which make sense in most cases. However, you should review these defaults and adjust for your project wherever necessary.

You will also find suggestions on what to change below.

Understanding the default configuration

Here is the current default config for version 2 Show archive.org snapshot :

config.permissions = 0644
config.directory_permissions = 0755
config.storage_engines = {
  :file => "CarrierWave::Storage::File",
  :fog  => "CarrierWave::Storage::Fog"
}
config.storage = :file
config.cache_storage = nil # (1)
config.fog_attributes = {}
config.fog_credentials = {}
config.fog_public = true
config.fog_authenticated_url_expiration = 600
config.fog_use_ssl_for_aws = true
config.fog_aws_accelerate = false
config.store_dir = 'uploads'
config.cache_dir = 'uploads/tmp'
config.delete_tmp_file_after_storage = true
config.move_to_cache = false
config.move_to_store = false
config.remove_previously_stored_files_after_update = true
config.downloader = CarrierWave::Downloader::Base
config.ignore_integrity_errors = true # (2)
config.ignore_processing_errors = true
config.ignore_download_errors = true
config.validate_integrity = true # (3)
config.validate_processing = true
config.validate_download = true
config.root = lambda { CarrierWave.root }
config.base_path = CarrierWave.base_path
config.enable_processing = true
config.ensure_multipart_form = true

Notes

  1. If no cache_storage is set, CarrierWave uses the configured storage for caching. Only set a value if you need a different type of cache storage.
  2. ignore_*_errors means "do not raise exceptions on error" (during caching). If you're performing uploads async, i.e. uploading files to cache and using the cache key to later store the upload to a model, you may set ignore_*_errors to false. This way, you'll be informed about errors already during upload, instead of later during model save.
  3. Your ActiveRecord instances will receive validation errors where validate_* = true.

"Integrity" is about valid files, e.g. matching extension white- or blacklists. "Processing" is about process calls, e.g. for changing image resolution. "Download" is when CarrierWave loads a file from a remote location via remote_<mounted_as>_url.

Suggested changes

  • We strongly suggest some kind of nested directory structure for performance reasons, unless you know you will be storing only a few files.
    For that, implement a store_dir instance method in your uploader (or an ApplicationUploader, if you have one). We have a separate card on how to do that.
    We suggest you also clear the store_dir config setting to avoid any confusion:

    config.store_dir = nil # Configured in the uploader
    
  • Do not implement cache_dir as an instance method on your uploader classes.
    While that works for uploading files and re-displaying uploaded (but not yet fully stored) files on form round trips, it breaks CarrierWave's clean_cached_files! method (see next item).
    If you want to specify a custom directory, just set it in the configuration:

    config.cache_dir = ...
    
  • Enable cleaning up old files from the cache directory. CarrierWave provides CarrierWave::Uploader::Base.clean_cached_files! for that already, but you need to call regularly from your preferred scheduler. For example, when using whenever, you should have something like this in your schedule.rb:

    every :day, at: '05:00', roles: [:cron] do
      runner 'ApplicationUploader.clean_cached_files!'
    end
    
  • When handling large files, consider enabling these options:

    config.move_to_cache = true
    config.move_to_store = true
    

    We have a separate card about that.

  • Store test files separately. Also add support for parallel tests. You can easily do that by setting config.root:

    config.root = "#{Rails.public_path}/system/#{Rails.env}#{ENV['TEST_ENV_NUMBER']}".freeze
    
  • For debugging purposes (e.g. trying to hunt down a staging bug locally), it might make sense to allow reading files from a separate environment. You you could read from an ENV variable instead of using your Rails.env.

Suggested configuration

In total, here is a suggested configuration that you can put into config/initializers/carrierwave.rb:

UPLOADER_ENV = (ENV['UPLOADER_ENV'] || Rails.env.to_s).freeze

CarrierWave.configure do |config|
  config.root = "#{Rails.public_path}/system/#{UPLOADER_ENV}#{ENV['TEST_ENV_NUMBER']}".freeze
  config.cache_dir = File.join(config.root, 'upload_cache').freeze
  config.store_dir = nil # Configured in the uploader

  # CarrierWave's `base_path` is not supposed to reference a file system path, but is used for URL generation.
  # Hence, it needs to be relative to the public directory, and start with a slash.
  config.base_path = config.root.delete_prefix(Rails.public_path.to_s).freeze
  
  # Optional: Move files instead of copying. Improves performance when dealing with large files, but may introduce caveats.
  # config.move_to_cache = true
  # config.move_to_store = true
end

And don't forget about the recurring task to clean cached files.

Dominik Schöler
Last edit
Over 1 year ago
Julian
License
Source code in this card is licensed under the MIT License.
Posted by Dominik Schöler to makandra dev (2021-02-24 15:55)