Rails Additional topics

Overview

Cloudinary is a cloud-based service that provides an end-to-end image management solution including uploads, storage, administration, image manipulation, and delivery.

Cloudinary's Ruby GEM wraps Cloudinary's upload API for easily uploading images and raw files to the cloud. In addition, the Ruby library simplifies the generation of image manipulation URLs and includes view helper methods for embedding images and transformed images in your web views.

This page includes additional details regarding the integration of Cloudinary with your Ruby on Rails applications.

Configuration options

Setting the configuration parameters can be done either directly in each call to a Cloudinary method or by globally setting using a YAML configuration file, a Rails initializer or an environment variable.

Your cloud_name account parameter is required to build image URLs. api_key and api_secret are further needed to perform secure API calls to Cloudinary (e.g., image uploads). See API, URLs and access identifiers for more details.

Configuration parameters can be globally set using a cloudinary.yml configuration file, located under the config directory of your Rails project.

You can download your customized cloudinary.yml configuration file through our Management Console.

Here's an example of a cloudinary.yml file:

production:
  cloud_name: "sample"
  api_key: "874837483274837"
  api_secret: "a676b67565c6767a6767d6767f676fe1"

You can always override the values specified in cloudinary.yml by passing different values in specific Cloudinary calls.

Another configuration option is to use a Rails initializer file. You can place a file named cloudinary.rb in the /config/initializers folder of your Rails project. Here's a sample initializer code:

Cloudinary.config do |config|
  config.cloud_name = 'sample'
  config.api_key = '874837483274837'
  config.api_secret = 'a676b67565c6767a6767d6767f676fe1'
  config.cdn_subdomain = true
end

One last configuration option allows you to dynamically configure the Cloudinary library by defining the CLOUDINARY_URL environment variable. The configuration URL is available in the Management Console's dashboard of your account. When using Cloudinary through a PaaS add-on (e.g., Heroku), this environment variable is automatically defined in your deployment environment. Here's a sample value:

CLOUDINARY_URL=cloudinary://874837483274837:a676b67565c6767a6767d6767f676fe1@sample

In addition to the three mandatory configuration parameters mentioned above, you can define various optional configuration parameters either globally or for each API call specifically. Optional parameters:

  • cdn_subdomain - Boolean (default: false). Whether to automatically build URLs with multiple CDN sub-domains. See this blog post for more details.
  • private_cdn - Boolean (default: false). Should be set to true for Advanced plan's users that have a private CDN distribution.
  • secure_distribution - The domain name of the CDN distribution to use for building HTTPS URLs. Relevant only for Advanced plan's users that have a private CDN distribution.
  • cname - Custom domain name to use for building HTTP URLs. Relevant only for Advanced plan's users that have a private CDN distribution and a custom CNAME.
  • static_image_support - Boolean (default: false). Whether to deliver uploaded static images through Cloudinary.
  • enhance_image_tag - Boolean (default: false). Whether to wrap the standard image_tag view helper's method. Set to true if static_image_support is set to true.
  • secure - Boolean (default: false). Force HTTPS URLs of images even if embedded in non-secure HTTP pages.

Sprite generation

Integrating a sprite in your view is very easy using the cl_sprite_tag helper method.

For example, for integrating a sprite that contains images that has the logo tag, add the following code to the head section of your HTML template:

cl_sprite_tag("logo")

Displaying an image with the public ID amazon_logo contained within the sprite:

<div class="amazon_logo"/>

You can also specify transformation instructions for running on all images before merging into the sprite. For example:

cl_sprite_tag("logo", :width => 150, :height => 60, :crop => :fit)

Refer to Sprite With Transformations for more details.

Sometimes you need to re-generate a sprite when its contained images change and you want to make sure that all users receive the updated sprite immediately (bypass cache).

To do this, you should directly request to generate the sprite. Calling this method returns the new version of the generated sprite, which you should use for integrating the sprite in your view. You can also let Cloudinary manage that for you.

The following example generates (or re-generates) a sprite and stores its version in a file on the local drive:

Cloudinary::Uploader.generate_sprite('logo', :version_store => :file)

In your view you can tell cl_sprite_tag to read the current version from the file in order to build a correct URL to deliver the latest version of the sprite:

cl_sprite_tag("logo", :version_store => :file)

Cloudinary Ruby GEM also provides a useful set of methods for managing tags of uploaded images.

Assign the given tag to images with the given list of Public IDs:

Include ':exclusive => true' in specified options if you wish to remove the given tag from all other resources.

Cloudinary::Uploader.add_tag(tag, public_ids = [], options = {})
Cloudinary::Uploader.add_tag('logo', 
                             ['amazon_logo', 'google_logo', 'apple_logo'])

Clear the given tag from images with the given list of Public IDs:

Cloudinary::Uploader.remove_tag(tag, public_ids = [], options = {})

For example:

Cloudinary::Uploader.remove_tag('logo',
                                ['microsoft_logo', 'hp_logo', 'rim_logo'])

Clear all existing tags from images with the given list of Public IDs and assign to all of them the given tag:

  Cloudinary::Uploader.replace_tag(tag, public_ids = [], options = {})

For example:

Cloudinary::Uploader.replace_tag('special_logo', 
                                 ['heroku_logo', 'engine_yard_logo'])

Attachinary

Attachinary is an attachment management library for Ruby on Rails. Attachinary was developed by Milovan Zogovic and it does an amazing job in simplifying attachment management in your application's model. Here are some advantages of Attachinary:

  • Attachinary offers non-intrusive integration with ActiveRecord and Mongoid model. You no longer need to maintain DB columns in your model entities for referencing uploaded images.
  • With attachinary it's very easy to switch between a single image and multiple images for a model entity.
  • Attachinary allows for simple integration through Rails modern Asset Pipeline.
  • Attachinary uses Cloudinary for uploading files to the cloud, transforming images and delivering files through a fast CDN. No need to install any image manipulation software.
  • Attachinary has built-in integration with Cloudinary's jQuery-based direct upload from the browser. Progress indication and image preview included.
  • Attachinary is extremely simple to use and requires minimal changes to your existing code base.

After a very quick Cloudinary & Attachinary GEM installation and setup, you can add any attachment attribute to your model class. The following code shows a User model entity:

class User < ActiveRecord::Base
  attr_accessible :name
  
  has_attachment  :avatar
  has_attachments :photos, :maximum => 3
end

The has_attachment and has_attachments methods were used to define a User that can have a single 'avatar' and up to 3 'photo' attachments. That's it, no additional migrations or code changes are required.

Uploading assets to Cloudinary is also quite simple with Attachinary. The following HAML view code shows how to create an upload form. The attachinary_file_field_tag view helper method is responsible for all the magic. When this form is submitted, all images will be automatically uploaded to the cloud directly from your website visitor's browser. Multiple photos can be uploaded from this same form and the identifiers of the uploaded images will be automatically stored in your model.

= form_for(@user) do |user_form|
    = user_form.text_field(:name)
    = attachinary_file_field_tag 'user[avatar]', @user, :avatar
    = attachinary_file_field_tag 'user[photos]', @user, :photos
    
    = user_form.submit("Save")

Model management in your controller is the same as always:

def create
  @user = User.new(params[:user])
  @user.save!
end

You can display uploaded images, generate thumbnails and apply image transformations by using Cloudinary's cl_image_tag. Here's an example of a view code that displays a 80x100 face detection based thumbnail of the user's avatar and a 70x50 rounded corner version of all uploaded photos.

- if user.avatar.present?
  = cl_image_tag(user.avatar.path, :width => 80, :height => 100,
                 :crop => :thumb, :gravity => :face)        
  - user.photos.each do |photo|
    = cl_image_tag(photo.path, :size => '70x50', :crop => :fill, :radius => 20)

Using attachinary allows you to dynamically apply any image transformation supported by Cloudinary. All transformed images are generated on-the-fly in the cloud and are then cached and delivered through a fast CDN.

Static images

While Cloudinary's service focuses on user uploaded images, you can use Cloudinary to manage the static images you have in your web application as well: background images, buttons, icons - they too should be delivered through a CDN, offloading their delivery from your servers and improving your website's performance.

Cloudinary's Ruby GEM simplifies and streamlines the process of uploading your static images to the cloud and delivering them through a CDN.

To upload all your Ruby-on-Rails applications' static images to Cloudinary, run the following Rake command:

rake cloudinary:sync_static

This Rake task finds all the images in all common public folders and in Rails Asset Pipeline’s image asset folders. Afterwards, it uploads all new and modified images to Cloudinary. Uploaded images and their versions are maintained using a local .cloudinary.static file. Make sure you commit this file to your source control.

After uploading your static images to Cloudinary, edit your cloudinary.yml file and set the following configuration parameters to 'true':

 enhance_image_tag: true
 static_image_support: true

Every image_tag call in your views would automatically check if the image was uploaded to the cloud (using .cloudinary.static) and if so, would generate a remote Cloudinary CDN URL. For example:

<%= image_tag(“logo.png”, :width => 100, :height => “100”) %>

May generate the following HTML code:

<img src=http://res.cloudinary.com/demo/image/static/
      logo-5740ed843b23d0b86e48081f43a45b9c width=100 height=100/>

The Ruby GEM automatically delivers background images defined in your CSS, SCSS or SASS files using the default image-url directly or Cloudinary's cloudinary-url custom directive.

See the following blog post for more details: How to deliver your static images through a CDN in Ruby on Rails

Admin API

While using Cloudinary, all your images are uploaded to the cloud. You can use our Media Library web interface to browse through your uploaded images and generated transformations.

In addition, you can use Cloudinary's administrative API: an intuitive RESTful HTTP API for programmatically managing all of your Cloudinary hosted assets. Main supported operations:

  • Listing all uploaded images and raw files.
  • Receiving details and metadata for uploaded images, including timestamps, format, dimensions, etc.
  • Listing the derived images of uploaded images.
  • Finding all images that share a given tag.
  • Listing all transformations.
  • Listing tags.
  • Receiving transformation details.
  • Creating named transformations.
  • Updating an existing transformation.
  • Deleting images, raw files, derived images and transformations.

For example, the following Ruby command returns the details of an uploaded image according to its public ID:

Cloudinary::Api.resource('sample')

# Sample output:
{
  "public_id": "sample",
  "format": "jpg",
  "version": 1312461204,
  "resource_type": "image",
  "type": "upload",
  "created_at": "2011-08-04T12:33:24Z",
  "bytes": 120253,
  "width": 864,
  "height": 576,
  "url": "http://res.cloudinary.com/demo/image/upload/v1312461204/sample.jpg",
  "secure_url": "https://.../image/upload/v1312461204/sample.jpg",
  "next_cursor": "041a39fc10971b9eabd4993470f6bfaf",
  "derived": [
    {
      "transformation": "c_fill,w_100,h_100",
      "format": "jpg",
      "bytes": 7112,
      "id": "8267a869b62a93a59248f35d7f124c1f",
      "url": "http://.../demo/image/upload/c_fill,w_100,h_100/v1312461204/sample.jpg",
      "secure_url": "https://.../image/upload/c_fill,w_100,h_100/v1312461204/sample.jpg"
    },
    {
      "transformation": "w_230,h_168,c_fit",
      "format": "jpg",
      "bytes": 19173,
      "id": "383e22a57167445552a3cdc16f0a0c85",
      "url": "http://.../demo/image/upload/w_230,h_168,c_fit/v1312461204/sample.jpg",
      "secure_url": "https://.../image/upload/w_230,h_168,c_fit/v1312461204/sample.jpg"
    }
  ]
 }

For a general overview and more examples, see this blog post: RESTful API for managing your website's images and other online assets

For more details, see our complete reference of the Admin API.

Migration

If your web application is already live in production with many resources already uploaded and stored somewhere, you can use the Cloudinary migration tool for Ruby.

This tool allows you to manage the migration process: upload all resources to Cloudinary, perform the uploading quickly using multiple worker threads, handle communication errors, and allow pausing and resuming the migration process at any time.

In order to use the migration tool, you need to install the sqlite3 Ruby GEM ('gem install sqlite3'), in addition to the Cloudinary GEM.

The following is an example of migration code that migrates all images of the Post entities that are stored in a database:

migrator = Cloudinary::Migrator.new(
  :retrieve=>proc{|id| Post.find(id).data }, 
  :complete=>proc{|id|, result| $stderr.print "done #{id} #{result}\n" }
  )

Post.find_each(:conditions=>["id > ?", migrator.max_given_id], :select => "id") do
  |post|
  migrator.process(:id => post.id, :public_id => "post_#{post.id}")
end
migrator.done

When constructing the Migrator object you can provide the following parameters:

  • :retrieve - A method that is called on a given ID you recognize. It must return the resource to upload in one of the following formats:
    • A public HTTP URL.
    • The actual content of the resource.
    • An IO stream for reading the resource's content.
    • An ActiveRecord::Base instance.
    • A Cloudinary::CarrierWave instance.
  • :complete - A callback method that is called when a resource was successfully uploaded. The method receives the internal ID of the resource and the result returned from the server (that includes the Public ID and the version).
  • :threads (Optional) - Number of worker threads to run simultaneously. An integer value between 1 and 100. Default: 10
  • :debug (Optional) - Print debugging information while migrating resources. Default: false.
  • :api_key and :api_secret unless they are configured in cloudinary.yml.

You need to feed the migrator with resources to upload. This is done by calling the process method which adds the received resource details to a persistent queue. The process method accepts the following parameters:

  • :id - An internal ID you need to provide for recognizing your resources during the migration process.
  • :public_id (Optional) - A Cloudinary Public ID to assign to an image resource. A random Public ID is generated.
  • :url (Optional) - A public HTTP URL of a an image. If specified, you don't have to provide the:retrieve method to the migration constructor.
  • Additional upload parameters (Optional) - You can specify additional standard upload parameters to send to Cloudinary while uploading the image: tags, transformation instructions, and eager transformations.

Note: If you want to use multiple upload threads and you fetch your resources using a database using Rails connections, make sure that the database connection pool size is at least number-of-threads+1. To ensure this, edit config/database.yml and add the following line to the file::

pool: 12