
> ## Documentation Index
> This page is part of the Image and Video APIs product. Fetch the complete documentation index for Image and Video APIs at: https://cloudinary.com/documentation/llms-image-and-video-apis.txt?referrer=docpage and then use it to discover all relevant pages before exploring further.
> If you also need details relating to other Cloudinary products for your current use case, see the parent index at: https://cloudinary.com/documentation/llms.txt?referrer=docpage

# CarrierWave integration


If you support dynamically uploading images in your Ruby on Rails application, the images are probably attached to a certain model entity. Rails uses **ActiveRecord** for model entities by default, while **Mongoid** documents are used for a MongoDB-based model. Examples might include keeping the image as the 'picture' attribute of a Post entity or as the 'profile_picture' attribute of a User entity.
  
The [CarrierWave](https://github.com/carrierwaveuploader/carrierwave) gem can be useful for integrating image uploads with your model. By default, CarrierWave stores images on the local hard drive, but it also has additional plugins available for image storing and transformation. 
  
The Cloudinary gem provides a plugin for CarrierWave. Using this plugin enables you to enjoy the benefits of CarrierWave for easily uploading images from HTML forms to your model, while enjoying the great benefits of Cloudinary: uploaded images are stored in cloud, transformed in the cloud, and delivered automatically through a CDN.

## CarrierWave installation and setup

To use the *optional* integration module for uploading images with ActiveRecord or Mongoid using CarrierWave, install the **CarrierWave** gem:
  
```ruby
gem install carrierwave
```

Rails 3.x Gemfile:

```ruby
gem 'carrierwave'
gem 'cloudinary'
```

Rails 5.x environment.rb

```ruby
config.gem 'carrierwave', version: '~> 0.4.10'
config.gem 'cloudinary'
```

> **NOTE**: The CarrierWave gem should be loaded before the Cloudinary gem.
  
## Upload examples

The following examples walk through using Cloudinary with CarrierWave in a Rails project. It uses a Post model with a `picture` attribute (a String column) to attach an image to each post.

To get started, define a CarrierWave uploader class and include the Cloudinary plugin. For details, see the [CarrierWave documentation](https://github.com/carrierwaveuploader/carrierwave).

### Define the uploader with tags and versions

This example converts the uploaded image to a PNG before storing it in the cloud. It also assigns it the `post_picture` tag. Then it defines two additional transformations required for displaying the image on the site: `standard` and `thumbnail`. A randomly generated unique public ID is assigned to each uploaded image and stored in the model.  
    
```ruby
class PictureUploader < CarrierWave::Uploader::Base

  include Cloudinary::CarrierWave

  process convert: 'png'
  process tags: ['post_picture']
  
  version :standard do
    process resize_to_fill: [100, 150, :north]
  end
  
  version :thumbnail do
    resize_to_fit(50, 50)
  end

end
```

### Set a custom public ID and mount the uploader

The following example explicitly defines a public_id based on the content of the 'short_name' attribute of the 'Post' entity. 

```ruby
class PictureUploader < CarrierWave::Uploader::Base      
  include Cloudinary::CarrierWave

  ...
        
  def public_id
    return model.short_name
  end  
end
```

You can also define a folder path as part of the `public_id`. For example, the following uploader stores uploaded assets under the `my_folder` folder and uses the `short_name` attribute of the `Post` entity as the rest of the public ID.

```ruby
class PictureUploader < CarrierWave::Uploader::Base      
  include Cloudinary::CarrierWave

  ...
        
  def public_id
    return "my_folder/#{model.short_name}"
  end  
end
```

If you prefer a randomly generated public ID while still storing the uploaded asset in a specific folder, you can return a folder-prefixed random ID:

```ruby
class PictureUploader < CarrierWave::Uploader::Base      
  include Cloudinary::CarrierWave

  ...
        
  def public_id
    return "my_folder/#{Cloudinary::Utils.random_public_id}"
  end  
end
```

If you're using direct uploading from the browser, you can also pass folder-related upload options in your form helper. For example:

```ruby
<%= f.cl_image_upload(:image, :folder => "my_folder") %>
```

The 'picture' attribute of Post is simply a String (a DB migration script is needed of course). It's mounted to the 'PictureUploader' class:
  
```ruby
class Post < ActiveRecord::Base
  ...
  mount_uploader :picture, PictureUploader
  ...
end
```

### Add the form, cache field, and controller save

In the HTML form for Post editing, this example adds a File field for uploading the picture and also a hidden 'cache' field for supporting page reloading and validation errors without losing the uploaded picture. The example below is in 'HAML' (you can of course do exactly the same using 'ERB'):
  
```ruby
= form_for(:post) do |post_form|
  = post_form.hidden_field(:picture_cache)
  = post_form.file_field(:picture)
```

In the controller, save or update the attributes of the post in the standard way. For example:

```ruby
post.update_attributes(params[:post])
```

> **NOTE**: If you are [uploading images from the browser directly to Cloudinary](rails_image_and_video_upload#direct_uploading_from_the_browser), a signed identifier is sent to the controller instead of the actual image data. Cloudinary's CarrierWave plugin seamlessly handles direct identifiers, verifies the signature, and updates the model with a reference to the uploaded image.

### Eagerly generate versions and display images

At this point, the image uploaded by the user to your server is uploaded to Cloudinary, which also assigned the specified public ID and tag and converts it to PNG. The public ID together with the version of the uploaded image are stored in the 'picture' attribute of the Post entity. Note that by default the transformations are not generated at this point; they are generated only when an end-user accesses them for the first time. This is true unless you specify 'process eager: true' or simply 'eager' for each transformation.

```ruby
class PictureUploader < CarrierWave::Uploader::Base
  include Cloudinary::CarrierWave

  version :standard do
    process eager: true
    process resize_to_fill: [100, 150, :north]          
  end
  
  version :thumbnail do
    eager
    resize_to_fit(50, 50)
  end
end
```

Now you can use standard `image_tag` calls for displaying the uploaded images and their derived transformations and the Cloudinary gem automatically generates the correct full URL for accessing your resources:
  
```ruby
image_tag(post.picture_url, alt: post.short_name)

image_tag(post.picture_url(:thumbnail), width: 50, height: 50)
```  

> **TIP**: **Access uploaded dimensions from your model**

When using CarrierWave with Cloudinary, you can access the uploaded asset’s dimensions from the mounted attribute’s metadata hash. Ensure your callback is after mount_uploader:

```ruby
# app/models/post.rb
class Post < ApplicationRecord
  mount_uploader :picture, PictureUploader
  after_save :update_dimensions

  private
  def update_dimensions
    if picture.present? && picture.metadata.present?
      w = picture.metadata["width"]
      h = picture.metadata["height"]
      # e.g., persist to columns or use as needed
      # update_columns(width: w, height: h)
    end
  end
end
```

The standard upload response already includes width and height; the snippet above shows how to retrieve them directly from the CarrierWave-mounted attribute in Rails.

### Return media metadata and colors

You can ask Cloudinary to include media metadata (IPTC/XMP/EXIF) and predominant colors in the upload response.

Server-side (CarrierWave uploader)

```ruby
# app/uploaders/picture_uploader.rb
class PictureUploader < CarrierWave::Uploader::Base
  include Cloudinary::CarrierWave

  # Request media metadata and color analysis in the upload response
  process media_metadata: true
  process colors: true

  # Optional: transform/convert
  process convert: 'png'
end
```

Accessing the metadata in your model

```ruby
# app/models/post.rb
class Post < ApplicationRecord
  mount_uploader :picture, PictureUploader

  after_save :extract_metadata

  private

  def extract_metadata
    return unless picture&.metadata.present?
    # Prefer media_metadata. image_metadata is deprecated but may exist on older assets.
    exif = picture.metadata['media_metadata'] || picture.metadata['image_metadata']
    palette = picture.metadata['colors'] # array of [color, percentage]
    # ... use as needed
  end
end
```

Client-side uploads (Rails helper)

```ruby
<%= cl_image_upload_tag(:image_id, media_metadata: true, colors: true) %>
```

Retrieve metadata for existing assets (Admin API)

```ruby
# By asset ID:
Cloudinary::Api.resource_by_asset_id(asset_id,
  media_metadata: true, colors: true)

# Or by public ID:
Cloudinary::Api.resource(public_id,
  media_metadata: true, colors: true)
  ```

> **NOTE**: `image_metadata` and `exif` upload options are deprecated. Use `media_metadata` to return IPTC, XMP, and detailed EXIF where available.

### Apply a transformation to all versions

If you define multiple versions in your CarrierWave uploader and want to apply the same transformation across all of them, use the `process_all_versions` helper provided by the Cloudinary CarrierWave plugin.

```ruby
class PictureUploader < CarrierWave::Uploader::Base
  include Cloudinary::CarrierWave

  # Apply a Cloudinary transformation to all versions defined below
  process_all_versions cloudinary_transformation: { effect: :sepia }

  version :standard do
    process resize_to_fill: [100, 150, :north]
  end

  version :thumbnail do
    resize_to_fit(50, 50)
  end
end
```

The `cloudinary_transformation` processor accepts any options supported by Cloudinary image transformations (for example, `effect`, `quality`, `crop`, `width`, and `height`). See the [Transformation reference](https://cloudinary.com/documentation/transformation_reference) for details.

### Compute dimensions before upload
For cases where you need to compute target dimensions prior to upload, you can inspect the local file in a CarrierWave process step and return a transformation hash. For example:

```ruby
# app/uploaders/picture_uploader.rb
class PictureUploader < CarrierWave::Uploader::Base
  include Cloudinary::CarrierWave

  process :set_width_height

  def set_width_height
    img = ::MiniMagick::Image.read(File.binread(@file.file))
    width  = img[:width]
    height = img[:height]
    # Apply your own logic here to derive new_width/new_height
    new_width  = width
    new_height = height
    { crop: :fill, width: new_width, height: new_height }
  end
end
```

This approach lets you base incoming transformation parameters on properties of the local file before it’s uploaded to Cloudinary.

### Setting the delivery type for CarrierWave uploads

By default, assets uploaded with CarrierWave use Cloudinary's `upload` delivery type, which makes the asset publicly accessible by CDN URL unless additional access controls are applied.

If you want to restrict access at upload time, set the uploader's `storage_type` to one of Cloudinary's restricted delivery types:

```ruby
class PictureUploader < CarrierWave::Uploader::Base
  include Cloudinary::CarrierWave

  self.storage_type = :private
end
```

Use **:private** to restrict access to the original asset while still allowing delivery of derived assets by URL. To also restrict derived assets, combine this with [Strict Transformations](control_access_to_media#strict_transformations). 

For details, see [Uploading as private assets](upload_parameters#private_assets) and [Controlling access to private media assets](control_access_to_media#private_media_assets).

```ruby
class PictureUploader < CarrierWave::Uploader::Base
  include Cloudinary::CarrierWave

  self.storage_type = :authenticated
end
```

Use **:authenticated** to restrict access to both the original asset and derived assets. 

For details, see [Uploading as authenticated assets](upload_parameters#authenticated_assets) and [Controlling access to authenticated media assets](control_access_to_media#authenticated_media_assets).

## Reusing existing Cloudinary assets with CarrierWave
In some cases, you may want to associate an asset that already exists in your Cloudinary product environment with additional model records without uploading the file again. For example, you might reuse the same image for multiple records that share a common thumbnail.

When you use `include Cloudinary::CarrierWave`, the mounted column (for example, `image_cloudinary` or `picture`) stores an internal identifier string that includes the resource type, delivery type (`type`), version, public ID, and format.

### Reusing the asset from another model
If you already have a model with a Cloudinary-backed uploader mounted, you can reuse its stored asset in a different model by wrapping the existing identifier in a `Cloudinary::CarrierWave::StoredFile:`

```ruby
# Existing record with an image already stored in Cloudinary
original = OriginalModel.find(params[:id])

image_cloudinary =
  if original.image_cloudinary.present?
    Cloudinary::CarrierWave::StoredFile.new(original.image_cloudinary.identifier)
  end

# New record that should point to the same Cloudinary asset
NewModel.create!(
  image_cloudinary: image_cloudinary,
  # other attributes...
)
```

This creates a new database record that references the same Cloudinary asset, without performing another upload or duplicating the asset in storage.

### Reusing an asset based on its details
If you know the asset’s details (for example, from a previous upload response or from the Admin API), you can reconstruct the identifier string and use it with `Cloudinary::CarrierWave::StoredFile`:

```ruby
resource_type = "image"
type         = "upload"
version      = 1_234_567_890
public_id    = "myimage"
format       = "jpg"

identifier = "#{resource_type}/#{type}/v#{version}/#{public_id}.#{format}"

NewModel.create!(
  image_cloudinary: Cloudinary::CarrierWave::StoredFile.new(identifier),
  # other attributes...
)
```

You can obtain the `resource_type`, `type`, `version`, `public_id`, and `format` from:
- The original upload response, or
- The Admin API (get details of a single resource [by public ID](admin_api#get_details_of_a_single_resource_by_public_id)  or [by asset ID](admin_api#get_details_of_a_single_resource_by_asset_id)).

### Avoiding accidental deletion of reused assets
By default, when a model that has a Cloudinary-backed uploader is destroyed, the associated Cloudinary asset is deleted as well. If you reuse the same asset across multiple records, you may want to prevent deleting the asset while it's still referenced by other models.

You can control this behavior by overriding the `delete_remote` method in your uploader:

```ruby
class ImageUploader < CarrierWave::Uploader::Base
  include Cloudinary::CarrierWave

  # Only delete the Cloudinary asset when this is the last record
  def delete_remote?
    identifier = model.read_attribute(mounted_as)&.identifier
    return false unless identifier

    # Replace :image_cloudinary with your mounted column name
    model.class.where(mounted_as => identifier).count == 1
  end
end
```

Adjust the condition in `delete_remote` to match your association logic. For example, you can check a join table, a usage counter, or any other rule that determines when an asset is no longer used anywhere in your application.
  
## Custom and dynamic transformations
  
Cloudinary's plugin for CarrierWave supports all standard CarrierWave resize and crop options. In addition, you can apply any custom transformation supported by Cloudinary using the `cloudinary_transformation` method. Calling `cloudinary_transformation` can be also done in combination with the standard CarrierWave resize and crop methods. The following uploader class shows a common example of using custom transformations: 
       
```ruby
class PictureUploader < CarrierWave::Uploader::Base      
  include Cloudinary::CarrierWave
  
  # Generate a 164x164 JPG of 80% quality 
  version :simple do
    process resize_to_fill: [164, 164, :fill]
    process convert: 'jpg'
    cloudinary_transformation quality: 80
  end
  
  # Generate a 100x150 face-detection based thumbnail, 
  # round corners with a 20-pixel radius and increase brightness by 30%.
  version :bright_face do
    cloudinary_transformation effect: "brightness:30", radius: 20,
      width: 100, height: 150, crop: "thumb", gravity: "face"
  end

end
```

You can take this further and apply chained transformations to achieve more complex results. These transformations can be applied as an incoming transformation while uploading or as part of the different versions that are generated either lazily or eagerly while uploading. The following uploader class includes such chained transformations applied using the `transformation` parameter of the `cloudinary_transformation` method.

```ruby
class PictureUploader < CarrierWave::Uploader::Base      
  include Cloudinary::CarrierWave
 
  # Apply an incoming chained transformation: limit image to 1000x1200 and 
  # add a 30-pixel watermark 5 pixels from the south east corner.   
  cloudinary_transformation transformation: [
      {width: 1000, height: 1200, crop: "limit"}, 
      {overlay: "my_watermark", width: 30, gravity: "south_east", 
       x: 5, y: 5}
    ]        
  
  # Eagerly transform image to 150x200 with a sepia effect applied and then
  # rotate the resulting image by 10 degrees. 
  version :rotated do
    eager
    cloudinary_transformation transformation: [
        {width: 150, height: 200, crop: "fill", effect: "sepia"}, 
        {angle: 10}
      ]
  end
end
```    

Some websites have a graphic design that forces them to display the same images in many different dimensions. Formally defining multiple uploader versions can be a hassle. You can still use CarrierWave and leverage Cloudinary's dynamic transformations by applying desired transformations while building your view. Any version can be generated dynamically from your view with no dependency on CarrierWave versions. To accomplish this, use the `full_public_id` attribute with `cl_image_tag` to build cloud-based transformation URLs for the uploaded images attached to your model.
        
```ruby   
cl_image_tag(post.picture.full_public_id, format: "jpg", width: 100, height: 200, 
             crop: "crop", x: 20, y: 30, radius: 10)
```    

## Custom coordinate-based cropping
  
If you allow your users to manually select the cropping area, it's recommended to keep the x,y coordinates persistently in the model to enable different cropping on the original image in the future. The following uploader class fetches the custom coordinates from attributes of the `model` object. The `custom_crop` method in this example returns a Hash of additional Cloudinary transformation parameters to apply.  
    
```ruby
class PictureUploader < CarrierWave::Uploader::Base  
  include Cloudinary::CarrierWave  

  version :full do    
    process convert: 'jpg'
    process :custom_crop
  end    
  
  def custom_crop      
    return x: model.crop_x, y: model.crop_y, 
      width: model.crop_width, height: model.crop_height, crop: "crop      "
  end
end
```

If you want to store only the cropped version of the image, you can use an [incoming transformation](eager_and_incoming_transformations##incoming_transformations). This way, the original image isn't stored in the cloud; only the cropped version. You can then use further transformations to resize the cropped image. The following example calls `process :custom_crop` in the class itself (instead of in a 'version') while the custom-coordinates are kept as transient attributes on the model (defined with `attr` instead of storing them persistently).

```ruby
class PictureUploader < CarrierWave::Uploader::Base  
  include Cloudinary::CarrierWave  

  process :custom_crop

  version :thumbnail do    
    process convert: 'jpg'
    resize_to_fill(120, 150, 'North')
  end    
  
  def custom_crop      
    return x: model.crop_x, y: model.crop_y, 
      width: model.crop_width, height: model.crop_height, crop: "crop      "
  end
end
```

## Legacy CarrierWave: Using the Original Filename as the public_id

> **NOTE**:
>
> This section applies to **legacy Ruby on Rails applications** that use **CarrierWave** with Cloudinary. For modern Rails integrations, prefer the `use_filename` and `unique_filename` upload options described elsewhere.

Older CarrierWave-based integrations may require explicitly defining the `public_id` in the uploader to preserve the original filename when uploading assets to Cloudinary.

### Server-side (CarrierWave uploader)

```ruby
def public_id
  Cloudinary::PreloadedFile.split_format(original_filename).first + "_"
end
```

This approach predates the `use_filename` and `unique_filename` upload options and is maintained here for backward compatibility with existing applications.

### Client-side uploads (form helper)

```erb
<%= form_for(@photo) do |f| %>
  <%= f.cl_image_upload(:image, use_filename: true) %>
<% end %>
```

For modern Rails apps, rely on the standard [upload options](rails_integration#upload_options) instead of overriding public_id manually.

&nbsp;Check out our Introduction to Cloudinary for Ruby Developers course in the Cloudinary Academy. This self-paced resource provides video-based lessons, sample scripts and other learning material to get you going with Ruby and Cloudinary today.