Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .cursor/rules/cloudinary.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
description: Cloudinary cloudinary_gem — agent guide
alwaysApply: true
---

Read and follow `AGENTS.md` in the repository root. It is the single
authoritative guide for this package: build/test commands, conventions,
gotchas, and when to use this SDK versus a sibling Cloudinary package.
5 changes: 5 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Cloudinary cloudinary_gem — instructions for AI coding agents

Read `AGENTS.md` in the repository root and follow it. It is the single
authoritative guide for this package: build/test commands, conventions,
gotchas, and when to use this SDK versus a sibling Cloudinary package.
63 changes: 63 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# AGENTS.md — cloudinary_gem

## What this package is (one line)
Official Cloudinary Ruby/Rails server SDK: upload assets, build transformation and delivery URLs/tags, call the Admin API, and wire Cloudinary into Active Storage or CarrierWave — all from a backend where the `api_secret` stays private.

## When to use this / when NOT to use this
- **Use this when:** you are in a Ruby or Rails server runtime (Rails app, Sinatra service, background job, plain script) and need signed uploads, asset administration, view tags (`cl_image_tag`, `cl_video_tag`), or signed delivery URLs.
- **Do NOT use this when:** you need browser-side delivery URLs in a JS frontend — use [`@cloudinary/url-gen`](https://github.com/cloudinary/js-url-gen), which builds URLs without exposing a secret. For a no-code/autonomous agent path, use the [Cloudinary MCP server](https://github.com/cloudinary/mcp-servers).
- **Sibling packages:** `@cloudinary/url-gen` = browser URL builder; [`attachinary`](https://github.com/cloudinary/attachinary) = legacy Rails attachment gem (prefer Active Storage for new apps). Stay on this gem's `1.x` line only for Ruby 1.9.3/2.x.

## Setup
```bash
gem install cloudinary # or add `gem "cloudinary"` to your Gemfile, then: bundle install
```
Required configuration / credentials — the SDK reads `CLOUDINARY_URL` automatically:
```bash
export CLOUDINARY_URL=cloudinary://<api_key>:<api_secret>@<cloud_name>
```

## Minimal runnable example
```ruby
require 'cloudinary' # CLOUDINARY_URL is picked up from the environment

# Upload a local file from the server (uses the api_secret — server-side only)
result = Cloudinary::Uploader.upload("my_picture.jpg")
puts result["public_id"]

# Build a 100x150 fill-crop delivery URL for an uploaded asset
puts Cloudinary::Utils.cloudinary_url("sample.jpg", width: 100, height: 150, crop: "fill")
```
In Rails views, prefer the `cl_image_tag("sample.jpg", width: 100, height: 150, crop: "fill")` helper.

## Build / test commands (run these after editing)
```bash
bundle install # install gem + dev dependencies
export CLOUDINARY_URL=cloudinary://<api_key>:<api_secret>@<cloud_name>
bundle exec rspec --format documentation --color # full suite (exactly what CI runs)
bundle exec rspec -f d # shorthand the project's CONTRIBUTING uses
bundle exec rspec spec/uploader_spec.rb # a single spec file
```
- No linter is configured (no `.rubocop.yml`, no rubocop in `cloudinary.gemspec`). Do not invent a `lint` task.
- `rake` / `rake spec` is the default Rake task and also runs the suite. `rake build` first runs `cloudinary:fetch_assets`.

## Conventions & gotchas
- **The test suite hits the live Cloudinary API.** Specs require a real `CLOUDINARY_URL` and a network connection — they are not fully hermetic. Use a throwaway/test cloud; some specs create and delete real assets. `rspec-retry` is enabled for flaky network specs.
- **Code must work both with and without Rails.** Rails-specific code lives in `lib/cloudinary/helper.rb`, `engine.rb`, `railtie.rb`, and `lib/active_storage/service/cloudinary_service.rb`; core API code (`uploader.rb`, `api.rb`, `utils.rb`, `search.rb`) must load in plain Ruby too.
- Source lives under `lib/cloudinary/`; the version is in `lib/cloudinary/version.rb`. Bump it there, not in the gemspec.
- HTTP goes through Faraday (`faraday`, `faraday-multipart`, `faraday-follow_redirects`) — keep new request code on that stack.
- **Never expose `api_secret` to a browser.** Signed uploads and signed URLs are exactly why this gem is server-side; do not port that logic to a frontend bundle.
- **Supported versions (2.x):** Ruby `>= 3, < 5`; Rails 6/7/8. CI matrix runs Ruby 3.1.7, 3.2.9, 3.3.10, 3.4.8, and 4.0.0.

## Canonical docs (leave the repo for depth)
- Ruby on Rails SDK guide: https://cloudinary.com/documentation/rails_integration
- Transformation & REST API reference: https://cloudinary.com/documentation/cloudinary_references
- MCP server (agent/no-code path): https://github.com/cloudinary/mcp-servers

## Agent / MCP note
If this capability is also exposed via the Cloudinary MCP servers, prefer the MCP tool for autonomous task execution and use this SDK for code generation. See cloudinary/mcp-servers.

## Commit / PR conventions
- Default branch is `master`; branch from it and open a PR against it (CI runs on pushes/PRs to `master`).
- Provide test code covering new behavior, and make sure it works **both with and without Rails** (per `CONTRIBUTING.md`).
- PR description must clearly state the bug/feature and reference the relevant issue number when applicable. The CI check "Ruby Test 💎" must pass across the Ruby matrix.
29 changes: 29 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@AGENTS.md

# CLAUDE.md — cloudinary_gem

## What this repo is

The official Cloudinary Ruby/Rails server SDK (`cloudinary` gem): signed uploads, Admin/Search API, transformation URL generation, Rails view helpers (`cl_image_tag`, `cl_video_tag`), and Active Storage / CarrierWave integration — all on the server where the `api_secret` stays private.

## Key constraints and gotchas

- **Test suite hits the live API.** Specs require a real `CLOUDINARY_URL` and network access — not hermetic. Use a throwaway cloud; some specs create and delete real assets. `rspec-retry` is enabled for flaky network specs.
- **`CLOUDINARY_URL` vs discrete vars conflict.** If `CLOUDINARY_CLOUD_NAME` is present in the environment, the gem ignores `CLOUDINARY_URL` and reads the discrete `CLOUDINARY_*` vars instead. Pick one style — don't mix them.
- **Rails-only helpers.** `cl_image_tag` / `cl_video_tag` load via Railtie and are only available where Action View helpers are (controllers, views, helpers). In a plain Ruby script or background job, use `Cloudinary::Utils.cloudinary_url(…)` instead.
- **No linter configured.** No `.rubocop.yml`, no rubocop in the gemspec. Don't invent a `lint` task.
- **Default branch is `master`.** Branch from it; CI ("Ruby Test 💎") runs on pushes/PRs to `master` across the Ruby matrix (3.1, 3.2, 3.3, 3.4, 4.0).
- **HTTP stack is Faraday.** Keep new request code on `faraday` / `faraday-multipart` / `faraday-follow_redirects` — don't add a second HTTP client.
- **Version bump:** edit `lib/cloudinary/version.rb` — not the gemspec.
- **Supported versions (2.x):** Ruby `>= 3, < 5`; Rails 6/7/8. For Ruby 1.9.3/2.x, stay on the 1.x line.

## Verified build and test commands

```bash
bundle install # install gem + dev dependencies
export CLOUDINARY_URL=cloudinary://<key>:<secret>@<cloud>
bundle exec rspec --format documentation --color # full suite (what CI runs)
bundle exec rspec -f d # shorthand the project uses
bundle exec rspec spec/uploader_spec.rb # single spec file
rake spec # equivalent via Rake
```
167 changes: 75 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,129 +1,112 @@
[![Build Status](https://app.travis-ci.com/cloudinary/cloudinary_gem.svg?branch=master)](https://app.travis-ci.com/github/cloudinary/cloudinary_gem)
[![Gem Version](https://badge.fury.io/rb/cloudinary.svg)](https://rubygems.org/gems/cloudinary)
[![Gem Version](https://badgen.net/rubygems/dt/cloudinary)](https://rubygems.org/gems/cloudinary)
# Cloudinary Ruby and Rails SDK

Cloudinary Ruby on Rails SDK
===================
[![Gem Version](https://img.shields.io/gem/v/cloudinary.svg)](https://rubygems.org/gems/cloudinary)
[![license](https://img.shields.io/badge/license-MIT-green.svg)](https://rubygems.org/gems/cloudinary)
[![CI](https://github.com/cloudinary/cloudinary_gem/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/cloudinary/cloudinary_gem/actions/workflows/ci.yml)

## About
The `cloudinary` gem is the server-side Cloudinary SDK for Ruby and Rails. Use it in a Rails app, a Sinatra service, a background job, or a plain Ruby script to upload assets, build transformation and delivery URLs, render view tags, and call the Admin API. It holds the API secret, so it handles the operations that can't run in a browser: signed uploads, signed delivery URLs, and asset administration. The current release (2.4.5) requires Ruby 3.x or 4.x.

The Cloudinary Ruby on Rails SDK allows you to quickly and easily integrate your application with Cloudinary.
Effortlessly optimize, transform, upload and manage your cloud's assets.

#### Note

This Readme provides basic installation and usage information. For the complete documentation, see
the [Ruby on Rails SDK Guide](https://cloudinary.com/documentation/rails_integration).

## Table of Contents

- [Key Features](#key-features)
- [Version Support](#Version-Support)
- [Installation](#installation)
- [Usage](#usage)
- [Setup](#Setup)
- [Transform and Optimize Assets](#Transform-and-Optimize-Assets)
- [CarrierWave Integration](#CarrierWave-Integration)
- [Active Storage Integration](#Active-Storage-Integration)

## Key Features

- [Transform](https://cloudinary.com/documentation/rails_video_manipulation#video_transformation_examples) and
[optimize](https://cloudinary.com/documentation/rails_image_manipulation#image_optimizations) assets.
- Generate [image](https://cloudinary.com/documentation/rails_image_manipulation#deliver_and_transform_images) and
[video](https://cloudinary.com/documentation/rails_video_manipulation#rails_video_transformation_code_examples) tags.
- [Asset Management](https://cloudinary.com/documentation/rails_asset_administration).
- [Secure URLs](https://cloudinary.com/documentation/video_manipulation_and_delivery#generating_secure_https_urls_using_sdks)
.

## Version Support
## Installation

| SDK Version | Ruby 1.9.3 | Ruby 2.x | Ruby 3.x | Ruby 4.x |
|-------------|------------|----------|----------|----------|
| 2.x | ✘ | ✘ | ✔ | ✔ |
| 1.x | ✔ | ✔ | ✔ | ✘ |
Add the gem to your `Gemfile`:

| SDK Version | Rails 5.x | Rails 6.x | Rails 7.x | Rails 8.x |
|-------------|-----------|-----------|-----------|-----------|
| 2.x | ✘ | ✔ | ✔ | ✔ |
| 1.x | ✔ | ✔ | ✔ | ✘ |
```ruby
gem "cloudinary"
```

## Installation
Then run `bundle install`. To install it directly:

```bash
gem install cloudinary
```

# Usage
## Configuration

### Setup
The SDK reads credentials automatically from the `CLOUDINARY_URL` environment variable:

```ruby
require 'cloudinary'
```bash
export CLOUDINARY_URL=cloudinary://<API_KEY>:<API_SECRET>@<CLOUD_NAME>
```

### Transform and Optimize Assets
- [See full documentation](https://cloudinary.com/documentation/rails_image_manipulation).
To set them in code instead, call `Cloudinary.config`:

```ruby
cl_image_tag("sample.jpg", width: 100, height: 150, crop: "fill")
require "cloudinary"

Cloudinary.config do |config|
config.cloud_name = "my_cloud_name"
config.api_key = "my_key"
config.api_secret = "my_secret"
config.secure = true
end
```

### Upload
- [See full documentation](https://cloudinary.com/documentation/rails_image_and_video_upload).
- [Learn more about configuring your uploads with upload presets](https://cloudinary.com/documentation/upload_presets).
Keep the API secret on the server. Don't put it in client-side code or commit it to version control.

## Quick examples

### Upload a file with the Ruby SDK

`Cloudinary::Uploader.upload` takes a local path, a remote URL, an IO or `File` object, or a data URI as its first argument. It's synchronous and returns a `Hash` of the parsed JSON response, including `public_id` and `secure_url`:

```ruby
Cloudinary::Uploader.upload("my_picture.jpg")
require "cloudinary"
# Credentials come from CLOUDINARY_URL in the environment.

result = Cloudinary::Uploader.upload("my_picture.jpg",
public_id: "cms/hero") # optional: where the asset lives in your media library
puts result["public_id"]
puts result["secure_url"]
```

### CarrierWave Integration
- [See full documentation](https://cloudinary.com/documentation/rails_carrierwave).
### Transform and optimize a delivery URL

`Cloudinary::Utils.cloudinary_url` is synchronous and returns a string — no network call. This one resizes to a 100x150 fill crop and lets Cloudinary pick the format and quality for the requesting browser (`f_auto`, `q_auto`):

### Active Storage Integration
- [See full documentation](https://cloudinary.com/documentation/rails_activestorage).
```ruby
require "cloudinary"

url = Cloudinary::Utils.cloudinary_url("sample.jpg",
width: 100, height: 150, crop: "fill",
fetch_format: :auto, quality: :auto)
# https://res.cloudinary.com/demo/image/upload/c_fill,f_auto,h_150,q_auto,w_100/sample.jpg
```

### Security options
- [See full documentation](https://cloudinary.com/documentation/solution_overview#security).
In a Rails view, the `cl_image_tag` helper renders a full `<img>` tag with the same options:

### Samples
- See [samples folder](https://github.com/cloudinary/cloudinary_gem/tree/master/samples).
```erb
<%= cl_image_tag("sample.jpg", width: 100, height: 150, crop: "fill", fetch_format: :auto, quality: :auto) %>
```

## Contributions
- See [CONTRIBUTING](CONTRIBUTING.md).
### Retrieve asset details

## Get Help
`Cloudinary::Api.resource` takes a public ID and returns the asset's metadata as a `Hash`, including its dimensions, format, and `secure_url`:

If you run into an issue or have a question, you can either:
```ruby
require "cloudinary"
# Credentials come from CLOUDINARY_URL in the environment.

- Issues related to the SDK: [Open a GitHub issue](https://github.com/cloudinary/cloudinary_gem/issues).
- Issues related to your account: [Open a support ticket](https://cloudinary.com/contact)
asset = Cloudinary::Api.resource("sample")
puts [asset["format"], asset["width"], asset["height"], asset["secure_url"]].join(" ")
```

## About Cloudinary
## For AI agents

Cloudinary is a powerful media API for websites and mobile apps alike, Cloudinary enables developers to efficiently
manage, transform, optimize, and deliver images and videos through multiple CDNs. Ultimately, viewers enjoy responsive
and personalized visual-media experiences—irrespective of the viewing device.
`cloudinary` is the Ruby and Rails server-side SDK. Choose it for backend upload, asset administration, view-tag and signed-URL generation, and Active Storage or CarrierWave integration, where the API secret stays private. The core classes (`Cloudinary::Uploader`, `Cloudinary::Api`, `Cloudinary::Utils`, `Cloudinary::Search`) load in plain Ruby; the `cl_image_tag` and `cl_video_tag` view helpers require Rails. For tasks this gem doesn't cover, choose a different package:

## Additional Resources
| Task | Package |
|---|---|
| Build delivery URLs in the browser | [`@cloudinary/url-gen`](https://github.com/cloudinary/js-url-gen) |
| Legacy Rails attachment handling | [`attachinary`](https://github.com/cloudinary/attachinary) — deprecated; prefer Active Storage |
| Run Cloudinary operations as agent tools | [Cloudinary MCP servers](https://github.com/cloudinary/mcp-servers) |

- [Cloudinary Transformation and REST API References](https://cloudinary.com/documentation/cloudinary_references):
Comprehensive references, including syntax and examples for all SDKs.
- [MediaJams.dev](https://mediajams.dev/): Bite-size use-case tutorials written by and for Cloudinary Developers
- [DevJams](https://www.youtube.com/playlist?list=PL8dVGjLA2oMr09amgERARsZyrOz_sPvqw): Cloudinary developer podcasts on
YouTube.
- [Cloudinary Academy](https://training.cloudinary.com/): Free self-paced courses, instructor-led virtual courses, and
on-site courses.
- [Code Explorers and Feature Demos](https://cloudinary.com/documentation/code_explorers_demos_index): A one-stop shop
for all code explorers, Postman collections, and feature demos found in the docs.
- [Cloudinary Roadmap](https://cloudinary.com/roadmap): Your chance to follow, vote, or suggest what Cloudinary should
develop next.
- [Cloudinary Facebook Community](https://www.facebook.com/groups/CloudinaryCommunity): Learn from and offer help to
other Cloudinary developers.
- [Cloudinary Account Registration](https://cloudinary.com/users/register/free): Free Cloudinary account registration.
- [Cloudinary Website](https://cloudinary.com): Learn about Cloudinary's products, partners, customers, pricing, and
more.
## Links

## Licence
- [Ruby on Rails SDK guide](https://cloudinary.com/documentation/rails_integration)
- [Upload](https://cloudinary.com/documentation/rails_image_and_video_upload)
- [Asset administration (Admin API)](https://cloudinary.com/documentation/rails_asset_administration)
- [Transformation and API references](https://cloudinary.com/documentation/cloudinary_references)
- [Documentation llms.txt index](https://cloudinary.com/documentation/llms.txt)
- [Gem on RubyGems](https://rubygems.org/gems/cloudinary)

Released under the MIT license.